Skip to content

Commit

Permalink
feat: setup assemble
Browse files Browse the repository at this point in the history
  • Loading branch information
IgnaceMaes committed Apr 27, 2024
1 parent 94b2d22 commit 35af678
Show file tree
Hide file tree
Showing 7 changed files with 625 additions and 256 deletions.
242 changes: 242 additions & 0 deletions bin/assemble.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
#!/usr/bin/env node
import fs from "fs";
import path from "path";
import chalk from "chalk";
import * as url from "url";

import { icons } from "../core/src/icons.js";

const __dirname = url.fileURLToPath(new URL(".", import.meta.url));

const ASSETS_PATH = path.join(__dirname, "../core/assets");
const COMPONENTS_PATH = path.join(__dirname, "../ember-phosphor-icons/src/components");
const INDEX_PATH = path.join(__dirname, "../src/index.ts");

if (!fs.existsSync(ASSETS_PATH)) {
console.error(
`${chalk.inverse.red(
" FAIL ",
)} Could not find assets directory, please make sure all git submodules are initialized and up to date.`,
);
process.exit(1);
}

const mappings = readFiles();

generateComponents(mappings);
generateExports(mappings);

console.log(chalk.green(`Compiled ${Object.keys(mappings).length} icons`));

function readFiles(): Record<string, Record<string, string>> {
const mappings = {};

const variants = fs.readdirSync(ASSETS_PATH, "utf-8");

variants.forEach((variant) => {
const variantPath = path.join(ASSETS_PATH, variant);

// Skip non-directories
if (!fs.lstatSync(variantPath).isDirectory()) return;

// Read all icons in variant
const icons = fs.readdirSync(variantPath, "utf-8");

icons.forEach((icon) => {
let key: string | undefined = undefined;
if (variant === "regular") {
key = icon.replace(".svg", "");
} else {
key = icon.replace(".svg", "").split("-").slice(0, -1).join("-");
}
// Create variant object if it doesn't exist
if (!mappings[key]) mappings[key] = {};

const iconPath = path.join(variantPath, icon);
// Skip directories
if (fs.lstatSync(iconPath).isDirectory()) return;

mappings[key][variant] = readFile(iconPath);
});
});

return mappings;
}

function readFile(path: string) {
return fs
.readFileSync(path)
.toString("utf-8")
.replace(/<svg.*?>/g, "")
.replace(/<\/svg>/g, "");
}

// function checkFiles(icon) {
// const weightsPresent = Object.keys(icon);
// return (
// weightsPresent.length === 6 &&
// weightsPresent.every((w) => weights.includes(w))
// );
// }

function generateComponents(mappings: Record<string, Record<string, string>>) {
let passes = 0;
let fails = 0;

if (fs.existsSync(COMPONENTS_PATH)) {
fs.rmSync(COMPONENTS_PATH, { recursive: true });
}

fs.mkdirSync(COMPONENTS_PATH);

for (const icon in mappings) {
const variants = mappings[icon];

const name = pascalize(icon);

const content = Object.entries(variants)
.map(([variant, content], index) => {
return `\n<g v-${
index > 0 ? "else-" : ""
}if="displayWeight === '${variant}'">${content}</g>`;
})
.join("");

const componentString = `\
/* GENERATED FILE */
import Component from '@glimmer/component';
interface Ph${name}Signature {
Args: {
weight?: 'thin' | 'light' | 'regular' | 'bold' | 'fill' | 'duotone';
size?: string | number;
color?: string;
mirrored?: boolean;
};
Blocks: {
default: [];
};
Element: SVGElement;
}
export default class Ph${name} extends Component<Ph${name}Signature> {
get weight() {
return this.args.weight ?? 'regular';
}
get size() {
return this.args.size ?? '1em';
}
get color() {
return this.args.color ?? 'currentColor';
}
get mirrored() {
const contextMirrored = this.args.mirrored ?? false;
return this.args.mirrored !== undefined
? this.args.mirrored
? 'scale(-1, 1)'
: undefined
: contextMirrored
? 'scale(-1, 1)'
: undefined;
}
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256"
width={{this.size}}
height={{this.size}}
fill={{this.color}}
transform={{this.mirrored}}
...attributes
>
{{yield}}
${content}
</svg>
</template>
}
`;
try {
fs.writeFileSync(
path.join(COMPONENTS_PATH, `Ph${name}.gts`),
componentString,
{
flag: "w",
},
);
console.log(`${chalk.inverse.green(" DONE ")} Ph${name}`);
passes += 1;
} catch (err) {
console.error(
`${chalk.inverse.red(" FAIL ")} Ph${name} could not be saved`,
);
console.group();
console.error(err);
console.groupEnd();
fails += 1;
}
}
}

function generateExports(mappings: Record<string, Record<string, string>>) {
const imports = Object.entries(mappings).map(([name]) => {
const pascalName = pascalize(name);

return `import Ph${pascalName} from "./icons/Ph${pascalName}.gts";`;
});

const exports: string[] = [];

Object.entries(mappings).forEach(([name]) => {
const iconData = icons.find((icon) => icon.name === name);

if (!iconData) {
throw new Error(`Could not find icon data for ${name}`);
}

exports.push(`Ph${iconData.pascal_name}`);

if ("alias" in iconData) {
exports.push(
`Ph${iconData.pascal_name} as Ph${iconData["alias"].pascal_name}`,
);
}
});

const indexString = `/* GENERATED FILE */
/* eslint-disable import/prefer-default-export */
${imports.join("\n")}
export {
${exports.join(",\n\t")}
}
`;

// .reduce(
// (acc, cur) => acc + cur,
// `/* GENERATED FILE */\n/* eslint-disable import/prefer-default-export */\n\n`,
// );

try {
fs.writeFileSync(INDEX_PATH, indexString, {
flag: "w",
});
console.log(chalk.green("Export success"));
} catch (err) {
console.error(chalk.red("Export failed"));
console.group();
console.error(err);
console.groupEnd();
}
}

function pascalize(str: string): string {
return str
.split("-")
.map((substr) => substr.replace(/^\w/, (c) => c.toUpperCase()))
.join("");
}
54 changes: 54 additions & 0 deletions bin/ph-icon.gts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import Component from '@glimmer/component';

interface Ph${name}Signature {
Args: {
weight?: 'thin' | 'light' | 'regular' | 'bold' | 'fill' | 'duotone';
size?: string | number;
color?: string;
mirrored?: boolean;
};
Blocks: {
default: [];
};
Element: SVGElement;
}

export default class Ph${name} extends Component<Ph${name}Signature> {
get weight() {
return this.args.weight ?? 'regular';
}

get size() {
return this.args.size ?? '1em';
}

get color() {
return this.args.color ?? 'currentColor';
}

get mirrored() {
const contextMirrored = this.args.mirrored ?? false;
return this.args.mirrored !== undefined
? this.args.mirrored
? 'scale(-1, 1)'
: undefined
: contextMirrored
? 'scale(-1, 1)'
: undefined;
}

<template>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256"
width={{this.size}}
height={{this.size}}
fill={{this.color}}
transform={{this.mirrored}}
...attributes
>
{{yield}}
${content}
</svg>
</template>
}
5 changes: 4 additions & 1 deletion ember-phosphor-icons/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
},
"dependencies": {
"@embroider/addon-shim": "^1.8.7",
"@glimmer/component": "^1.1.2",
"decorator-transforms": "^1.0.1"
},
"devDependencies": {
Expand Down Expand Up @@ -111,6 +112,8 @@
"version": 2,
"type": "addon",
"main": "addon-main.cjs",
"app-js": {}
"app-js": {
"./components/ph-icon.js": "./dist/_app_/components/ph-icon.js"
}
}
}
54 changes: 54 additions & 0 deletions ember-phosphor-icons/src/components/ph-icon.gts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import Component from '@glimmer/component';

interface PhIconSignature {
Args: {
weight?: 'thin' | 'light' | 'regular' | 'bold' | 'fill' | 'duotone';
size?: string | number;
color?: string;
mirrored?: boolean;
};
Blocks: {
default: [];
};
Element: SVGElement;
}

export default class PhIcon extends Component<PhIconSignature> {
get weight() {
return this.args.weight ?? 'regular';
}

get size() {
return this.args.size ?? '1em';
}

get color() {
return this.args.color ?? 'currentColor';
}

get mirrored() {
const contextMirrored = this.args.mirrored ?? false;
return this.args.mirrored !== undefined
? this.args.mirrored
? 'scale(-1, 1)'
: undefined
: contextMirrored
? 'scale(-1, 1)'
: undefined;
}

<template>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256"
width={{this.size}}
height={{this.size}}
fill={{this.color}}
transform={{this.mirrored}}
...attributes
>
<path d="M207.58,63.84C186.85,53.48,159.33,48,128,48S69.15,53.48,48.42,63.84,16,88.78,16,104v48c0,15.22,11.82,29.85,32.42,40.16S96.67,208,128,208s58.85-5.48,79.58-15.84S240,167.22,240,152V104C240,88.78,228.18,74.15,207.58,63.84ZM128,64c62.64,0,96,23.23,96,40s-33.36,40-96,40-96-23.23-96-40S65.36,64,128,64Zm-8,95.86v32c-19-.62-35-3.42-48-7.49V153.05A203.43,203.43,0,0,0,120,159.86Zm16,0a203.43,203.43,0,0,0,48-6.81v31.31c-13,4.07-29,6.87-48,7.49ZM32,152V133.53a82.88,82.88,0,0,0,16.42,10.63c2.43,1.21,5,2.35,7.58,3.43V178C40.17,170.16,32,160.29,32,152Zm168,26V147.59c2.61-1.08,5.15-2.22,7.58-3.43A82.88,82.88,0,0,0,224,133.53V152C224,160.29,215.83,170.16,200,178Z"></path>
{{yield}}
</svg>
</template>
}
10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,21 @@
"start:addon": "pnpm --filter ember-phosphor-icons start --no-watch.clearScreen",
"start:test-app": "pnpm --filter test-app start",
"test": "pnpm --filter '*' test",
"test:ember": "pnpm --filter '*' test:ember"
"test:ember": "pnpm --filter '*' test:ember",
"assemble": "tsx bin/assemble.ts"
},
"devDependencies": {
"@glint/core": "^1.2.1",
"@types/node": "^20.12.7",
"chalk": "^5.3.0",
"concurrently": "^8.2.0",
"prettier": "^3.0.3",
"prettier-plugin-ember-template-tag": "^1.1.0"
"prettier-plugin-ember-template-tag": "^1.1.0",
"tsx": "^4.7.3"
},
"pnpm": {
"overrides": {
"@types/eslint": "^7.0.0"
}
}
}
}
Loading

0 comments on commit 35af678

Please sign in to comment.