0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-26 06:31:26 -05:00

Merge pull request #4216 from penpot/niwinz-staging-gulp-replace

🎉 Replace gulp with node scripts
This commit is contained in:
Alejandro 2024-03-25 09:20:19 +01:00 committed by GitHub
commit f8bd0ba28a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 895 additions and 97 deletions

View file

@ -1,7 +1,7 @@
#!/usr/bin/env bash
export PATH=/usr/lib/jvm/openjdk/bin:/usr/local/nodejs/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
export JAVA_OPTS="-Xmx900m -Xms50m"
export JAVA_OPTS="-Xmx1000m -Xms50m"
alias l='ls --color -GFlh'
alias rm='rm -r'

View file

@ -19,12 +19,12 @@ popd
tmux -2 new-session -d -s penpot
tmux rename-window -t penpot:0 'gulp'
tmux rename-window -t penpot:0 'frontend watch'
tmux select-window -t penpot:0
tmux send-keys -t penpot 'cd penpot/frontend' enter C-l
tmux send-keys -t penpot 'npx gulp watch' enter
tmux send-keys -t penpot 'yarn run watch' enter
tmux new-window -t penpot:1 -n 'shadow watch'
tmux new-window -t penpot:1 -n 'frontend shadow'
tmux select-window -t penpot:1
tmux send-keys -t penpot 'cd penpot/frontend' enter C-l
tmux send-keys -t penpot 'clojure -M:dev:shadow-cljs watch main' enter

View file

@ -19,21 +19,17 @@
"scripts": {
"fmt:clj:check": "cljfmt check --parallel=false src/ test/",
"fmt:clj": "cljfmt fix --parallel=true src/ test/",
"test:compile": "clojure -M:dev:shadow-cljs compile test --config-merge '{:autorun false}'",
"lint:scss": "yarn run prettier -c resources/styles -c src/**/*.scss",
"lint:scss:fix": "yarn run prettier -c resources/styles -c src/**/*.scss -w",
"lint:clj": "clj-kondo --parallel --lint src/",
"test:compile": "clojure -M:dev:shadow-cljs compile test --config-merge '{:autorun false}'",
"test:run": "node target/tests.cjs",
"test:watch": "clojure -M:dev:shadow-cljs watch test",
"test": "yarn run test:compile && yarn run test:run",
"gulp:watch": "gulp watch",
"watch": "shadow-cljs watch main",
"validate-translations": "node ./scripts/validate-translations.js",
"find-unused-translations": "node ./scripts/find-unused-translations.js",
"build:clean": "gulp clean:output && gulp clean:dist",
"build:styles": "gulp build:styles",
"build:assets": "gulp build:assets",
"build:copy": "gulp build:copy",
"translations:validate": "node ./scripts/validate-translations.js",
"translations:find-unused": "node ./scripts/find-unused-translations.js",
"compile": "node ./scripts/compile.js",
"watch": "node ./scripts/watch.js",
"storybook:compile": "gulp template:storybook && clojure -M:dev:shadow-cljs compile storybook",
"storybook:watch": "npm run storybook:compile && concurrently \"clojure -M:dev:shadow-cljs watch storybook\" \"storybook dev -p 6006\"",
"storybook:build": "npm run storybook:compile && storybook build"
@ -67,19 +63,26 @@
"map-stream": "0.0.7",
"marked": "^12.0.0",
"mkdirp": "^3.0.1",
"mustache": "^4.2.0",
"nodemon": "^3.1.0",
"npm-run-all": "^4.1.5",
"p-limit": "^5.0.0",
"postcss": "^8.4.35",
"postcss-clean": "^1.2.2",
"prettier": "^3.2.5",
"pretty-time": "^1.1.0",
"prop-types": "^15.8.1",
"rimraf": "^5.0.5",
"sass": "^1.71.1",
"sass-embedded": "^1.71.1",
"shadow-cljs": "2.27.4",
"storybook": "^7.6.17",
"svg-sprite": "^2.0.2",
"typescript": "^5.3.3",
"vite": "^5.1.4",
"vitest": "^1.3.1"
"vitest": "^1.3.1",
"watcher": "^2.3.0",
"workerpool": "^9.1.0"
},
"dependencies": {
"date-fns": "^3.3.1",

View file

@ -26,7 +26,6 @@
<script>
window.penpotTranslations = JSON.parse({{& translations}});
window.penpotThemes = {{& themes}};
window.penpotVersion = "%version%";
window.penpotBuildDate = "%buildDate%";
</script>
@ -39,8 +38,8 @@
</head>
<body>
{{>../public/images/sprites/symbol/icons.svg}}
{{>../public/images/sprites/symbol/cursors.svg}}
{{> ../public/images/sprites/symbol/icons.svg }}
{{> ../public/images/sprites/symbol/cursors.svg }}
<div id="app"></div>
<section id="modal"></section>
{{# manifest}}

View file

@ -7,7 +7,6 @@
<link rel="icon" href="images/favicon.png" />
<script>
window.penpotThemes = {{& themes}};
window.penpotVersion = "%version%";
</script>

View file

@ -0,0 +1,405 @@
import proc from "node:child_process";
import fs from "node:fs/promises";
import ph from "node:path";
import os from "node:os";
import url from "node:url";
import * as marked from "marked";
import SVGSpriter from "svg-sprite";
import Watcher from "watcher";
import gettext from "gettext-parser";
import l from "lodash";
import log from "fancy-log";
import mustache from "mustache";
import pLimit from "p-limit";
import ppt from "pretty-time";
import wpool from "workerpool";
function getCoreCount() {
return os.cpus().length;
}
// const __filename = url.fileURLToPath(import.meta.url);
export const dirname = url.fileURLToPath(new URL(".", import.meta.url));
export function startWorker() {
return wpool.pool(dirname + "/_worker.js", {
maxWorkers: getCoreCount()
});
}
async function findFiles(basePath, predicate, options={}) {
predicate = predicate ?? function() { return true; }
let files = await fs.readdir(basePath, {recursive: options.recursive ?? false})
files = files.filter((path) => path.endsWith(".svg"));
files = files.map((path) => ph.join(basePath, path));
return files;
}
function syncDirs(originPath, destPath) {
const command = `rsync -ar --delete ${originPath} ${destPath}`;
return new Promise((resolve, reject) => {
proc.exec(command, (cause, stdout) => {
if (cause) { reject(cause); }
else { resolve(); }
});
});
}
export function isSassFile(path) {
return path.endsWith(".scss");
}
export function isSvgFile(path) {
return path.endsWith(".scss");
}
export async function compileSass(worker, path, options) {
path = ph.resolve(path);
log.info("compile:", path);
return worker.exec("compileSass", [path, options]);
}
export async function compileSassAll(worker) {
const limitFn = pLimit(4);
const sourceDir = "src";
let files = await fs.readdir(sourceDir, { recursive: true })
files = files.filter((path) => path.endsWith(".scss"));
files = files.map((path) => ph.join(sourceDir, path));
// files = files.slice(0, 10);
const procs = [
compileSass(worker, "resources/styles/main-default.scss", {}),
compileSass(worker, "resources/styles/debug.scss", {})
];
for (let path of files) {
const proc = limitFn(() => compileSass(worker, path, {modules: true}));
procs.push(proc);
}
const result = await Promise.all(procs);
return result.reduce((acc, item, index) => {
acc.index[item.outputPath] = item.css;
acc.items.push(item.outputPath);
return acc;
}, {index:{}, items: []});
}
function compare(a, b) {
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else {
return 0;
}
}
export function concatSass(data) {
const output = []
for (let path of data.items) {
output.push(data.index[path]);
}
return output.join("\n");
}
export async function watch(baseDir, predicate, callback) {
predicate = predicate ?? (() => true);
const watcher = new Watcher(baseDir, {
persistent: true,
recursive: true
});
watcher.on("change", (path) => {
if (predicate(path)) {
callback(path);
}
});
}
async function readShadowManifest() {
try {
const manifestPath = "resources/public/js/manifest.json"
let content = await fs.readFile(manifestPath, { encoding: "utf8" });
content = JSON.parse(content);
const index = {
config: "js/config.js?ts=" + Date.now(),
polyfills: "js/polyfills.js?ts=" + Date.now(),
};
for (let item of content) {
index[item.name] = "js/" + item["output-name"];
}
return index;
} catch (cause) {
// log.error("error on reading manifest (using default)", cause);
return {
config: "js/config.js",
polyfills: "js/polyfills.js",
main: "js/main.js",
shared: "js/shared.js",
worker: "js/worker.js",
rasterizer: "js/rasterizer.js",
};
}
}
async function renderTemplate(path, context={}, partials={}) {
const content = await fs.readFile(path, {encoding: "utf-8"});
const ts = Math.floor(new Date());
context = Object.assign({}, context, {
ts: ts,
isDebug: process.env.NODE_ENV !== "production"
});
return mustache.render(content, context, partials);
}
const renderer = {
link(href, title, text) {
return `<a href="${href}" target="_blank">${text}</a>`;
},
};
marked.use({ renderer });
async function readTranslations() {
const langs = [
"ar",
"ca",
"de",
"el",
"en",
"eu",
"it",
"es",
"fa",
"fr",
"he",
"nb_NO",
"pl",
"pt_BR",
"ro",
"id",
"ru",
"tr",
"zh_CN",
"zh_Hant",
"hr",
"gl",
"pt_PT",
"cs",
"fo",
"ko",
"lv",
"nl",
// this happens when file does not matches correct
// iso code for the language.
["ja_jp", "jpn_JP"],
// ["fi", "fin_FI"],
["uk", "ukr_UA"],
"ha"
];
const result = {};
for (let lang of langs) {
let filename = `${lang}.po`;
if (l.isArray(lang)) {
filename = `${lang[1]}.po`;
lang = lang[0];
}
const content = await fs.readFile(`./translations/${filename}`, { encoding: "utf-8" });
lang = lang.toLowerCase();
const data = gettext.po.parse(content, "utf-8");
const trdata = data.translations[""];
for (let key of Object.keys(trdata)) {
if (key === "") continue;
const comments = trdata[key].comments || {};
if (l.isNil(result[key])) {
result[key] = {};
}
const isMarkdown = l.includes(comments.flag, "markdown");
const msgs = trdata[key].msgstr;
if (msgs.length === 1) {
let message = msgs[0];
if (isMarkdown) {
message = marked.parseInline(message);
}
result[key][lang] = message;
} else {
result[key][lang] = msgs.map((item) => {
if (isMarkdown) {
return marked.parseInline(item);
} else {
return item;
}
});
}
// if (key === "modals.delete-font.title") {
// console.dir(trdata[key], {depth:10});
// console.dir(result[key], {depth:10});
// }
}
}
return JSON.stringify(result);
}
async function generateSvgSprite(files, prefix) {
const spriter = new SVGSpriter({
mode: {
symbol: { inline: true }
}
});
for (let path of files) {
const name = `${prefix}${ph.basename(path)}`
const content = await fs.readFile(path, {encoding: "utf-8"});
spriter.add(name, name, content);
}
const { result } = await spriter.compileAsync();
const resource = result.symbol.sprite;
return resource.contents;
}
async function generateSvgSprites() {
await fs.mkdir("resources/public/images/sprites/symbol/", { recursive: true });
const icons = await findFiles("resources/images/icons/", isSvgFile);
const iconsSprite = await generateSvgSprite(icons, "icon-");
await fs.writeFile("resources/public/images/sprites/symbol/icons.svg", iconsSprite);
const cursors = await findFiles("resources/images/cursors/", isSvgFile);
const cursorsSprite = await generateSvgSprite(icons, "cursor-");
await fs.writeFile("resources/public/images/sprites/symbol/cursors.svg", cursorsSprite);
}
async function generateTemplates() {
await fs.mkdir("./resources/public/", { recursive: true });
const translations = await readTranslations();
const manifest = await readShadowManifest();
let content;
const iconsSprite = await fs.readFile("resources/public/images/sprites/symbol/icons.svg", "utf8");
const cursorsSprite = await fs.readFile("resources/public/images/sprites/symbol/cursors.svg", "utf8");
const partials = {
"../public/images/sprites/symbol/icons.svg": iconsSprite,
"../public/images/sprites/symbol/cursors.svg": cursorsSprite,
};
content = await renderTemplate("resources/templates/index.mustache", {
manifest: manifest,
translations: JSON.stringify(translations),
}, partials);
await fs.writeFile("./resources/public/index.html", content);
content = await renderTemplate("resources/templates/preview-body.mustache", {
manifest: manifest,
translations: JSON.stringify(translations),
});
await fs.writeFile("./.storybook/preview-body.html", content);
content = await renderTemplate("resources/templates/render.mustache", {
manifest: manifest,
translations: JSON.stringify(translations),
});
await fs.writeFile("./resources/public/render.html", content);
content = await renderTemplate("resources/templates/rasterizer.mustache", {
manifest: manifest,
translations: JSON.stringify(translations),
});
await fs.writeFile("./resources/public/rasterizer.html", content);
}
export async function compileStyles() {
const worker = startWorker();
const start = process.hrtime();
log.info("init: compile styles")
let result = await compileSassAll(worker);
result = concatSass(result);
await fs.mkdir("./resources/public/css", { recursive: true });
await fs.writeFile("./resources/public/css/main.css", result);
const end = process.hrtime(start);
log.info("done: compile styles", `(${ppt(end)})`);
worker.terminate();
}
export async function compileSvgSprites() {
const start = process.hrtime();
log.info("init: compile svgsprite")
await generateSvgSprites();
const end = process.hrtime(start);
log.info("done: compile svgsprite", `(${ppt(end)})`);
}
export async function compileTemplates() {
const start = process.hrtime();
log.info("init: compile templates")
await generateTemplates();
const end = process.hrtime(start);
log.info("done: compile templates", `(${ppt(end)})`);
}
export async function compilePolyfills() {
const start = process.hrtime();
log.info("init: compile polyfills")
const files = await findFiles("resources/polyfills/");
let result = [];
for (let path of files) {
const content = await fs.readFile(path, {encoding:"utf-8"});
result.push(content);
}
await fs.mkdir("./resources/public/js", { recursive: true });
fs.writeFile("resources/public/js/polyfills.js", result.join("\n"));
const end = process.hrtime(start);
log.info("done: compile polyfills", `(${ppt(end)})`);
}
export async function copyAssets() {
const start = process.hrtime();
log.info("init: copy assets")
await syncDirs("resources/images/", "resources/public/images/");
await syncDirs("resources/fonts/", "resources/public/fonts/");
const end = process.hrtime(start);
log.info("done: copy assets", `(${ppt(end)})`);
}

View file

@ -0,0 +1,97 @@
import proc from "node:child_process";
import fs from "node:fs/promises";
import ph from "node:path";
import url from "node:url";
import * as sass from "sass-embedded";
import log from "fancy-log";
import wpool from "workerpool";
import postcss from "postcss";
import modulesProcessor from "postcss-modules";
import autoprefixerProcessor from "autoprefixer";
const compiler = await sass.initAsyncCompiler();
async function compileFile(path) {
const dir = ph.dirname(path);
const name = ph.basename(path, ".scss");
const dest = `${dir}${ph.sep}${name}.css`;
return new Promise(async (resolve, reject) => {
try {
const result = await compiler.compileAsync(path, {
loadPaths: ["node_modules/animate.css", "resources/styles/common/", "resources/styles"],
sourceMap: false
});
// console.dir(result);
resolve({
inputPath: path,
outputPath: dest,
css: result.css
});
} catch (cause) {
// console.error(cause);
reject(cause);
}
});
}
function configureModulesProcessor(options) {
const ROOT_NAME = "app";
return modulesProcessor({
getJSON: (cssFileName, json, outputFileName) => {
// We do nothing because we don't want the generated JSON files
},
// Calculates the whole css-module selector name.
// Should be the same as the one in the file `/src/app/main/style.clj`
generateScopedName: (selector, filename, css) => {
const dir = ph.dirname(filename);
const name = ph.basename(filename, ".css");
const parts = dir.split("/");
const rootIdx = parts.findIndex((s) => s === ROOT_NAME);
return parts.slice(rootIdx + 1).join("_") + "_" + name + "__" + selector;
},
});
}
function configureProcessor(options={}) {
const processors = [];
if (options.modules) {
processors.push(configureModulesProcessor(options));
}
processors.push(autoprefixerProcessor);
return postcss(processors);
}
async function postProcessFile(data, options) {
const proc = configureProcessor(options);
// We compile to the same path (all in memory)
const result = await proc.process(data.css, {
from: data.outputPath,
to: data.outputPath,
map: false,
});
return Object.assign(data, {
css: result.css
});
}
async function compile(path, options) {
let result = await compileFile(path);
return await postProcessFile(result, options);
}
wpool.worker({
compileSass: compile
}, {
onTerminate: async (code) => {
// log.info("worker: terminate");
await compiler.dispose();
}
});

View file

@ -1,4 +1,6 @@
#!/usr/bin/env bash
# NOTE: this script should be called from the parent directory to
# properly work.
set -ex
@ -12,13 +14,13 @@ export EXTRA_PARAMS=$SHADOWCLJS_EXTRA_PARAMS;
export NODE_ENV=production;
yarn install || exit 1;
yarn run build:clean || exit 1;
yarn run build:styles || exit 1;
rm -rf resources/public;
rm -rf target/dist;
clojure -J-Xms100M -J-Xmx1000M -J-XX:+UseSerialGC -M:dev:shadow-cljs release main --config-merge "{:release-version \"${CURRENT_HASH}\"}" $EXTRA_PARAMS || exit 1
clojure -M:dev:shadow-cljs release main --config-merge "{:release-version \"${CURRENT_HASH}\"}" $EXTRA_PARAMS || exit 1
yarn run build:assets || exit 1;
yarn run build:copy || exit 1;
yarn run compile || exit 1;
rsync -avr resources/public/ target/dist/
sed -i -re "s/\%version\%/$CURRENT_VERSION/g" ./target/dist/index.html;
sed -i -re "s/\%buildDate\%/$BUILD_DATE/g" ./target/dist/index.html;

View file

@ -0,0 +1,10 @@
import fs from "node:fs/promises";
import ppt from "pretty-time";
import log from "fancy-log";
import * as h from "./_helpers.js";
await h.compileStyles();
await h.copyAssets()
await h.compileSvgSprites()
await h.compileTemplates();
await h.compilePolyfills();

View file

@ -1,62 +0,0 @@
#!/usr/bin/env bash
# This script automates compressing PNG images using the lossless Zopfli
# Compression Algorithm. The process is slow but can produce significantly
# better compression and, thus, smaller file sizes.
#
# This script is meant to be run manually, for example, before making a new
# release.
#
# Requirements
#
# zopflipng - https://github.com/google/zopfli
# Debian/Ubuntu: sudo apt install zopfli
# Fedora: sudo dnf install zopfli
# macOS: brew install zopfli
#
# Usage
#
# This script takes a single positional argument which is the path where to
# search for PNG files. By default, the target path is the current working
# directory. Run from the root of the repository to compress all PNG images. Run
# from the `frontend` subdirectory to compress all PNG images within that
# directory. Alternatively, run from any directory and pass an explicit path to
# `compress-png` to limit the script to that path/directory.
set -o errexit
set -o nounset
set -o pipefail
readonly TARGET="${1:-.}"
readonly ABS_TARGET="$(command -v realpath &>/dev/null && realpath "$TARGET")"
function png_total_size() {
find "$TARGET" -type f -iname '*.png' -exec du -ch {} + | tail -1
}
echo "Compressing PNGs in ${ABS_TARGET:-$TARGET}"
echo "Before"
png_total_size
readonly opts=(
# More iterations means slower, potentially better compression.
#--iterations=500
-m
# Try all filter strategies (slow).
#--filters=01234mepb
# According to docs, remove colors behind alpha channel 0. No visual
# difference, removes hidden information.
--lossy_transparent
# Avoid information loss that could affect how images are rendered, see
# https://github.com/penpot/penpot/issues/1533#issuecomment-1030005203
# https://github.com/google/zopfli/issues/113
--keepchunks=cHRM,gAMA,pHYs,iCCP,sRGB,oFFs,sTER
# Since we have git behind our back, overwrite PNG files in-place (only
# when result is smaller).
-y
)
time find "$TARGET" -type f -iname '*.png' -exec zopflipng "${opts[@]}" {} {} \;
echo "After"
png_total_size

View file

@ -1,11 +0,0 @@
#!/usr/bin/env bash
# A repl useful for debug macros.
export OPTIONS="\
-J-XX:-OmitStackTraceInFastThrow \
-J-Xms50m -J-Xmx512m \
-M:dev:jvm-repl";
set -ex;
exec clojure $OPTIONS;

74
frontend/scripts/watch.js Normal file
View file

@ -0,0 +1,74 @@
import proc from "node:child_process";
import fs from "node:fs/promises";
import ph from "node:path";
import log from "fancy-log";
import * as h from "./_helpers.js";
import ppt from "pretty-time";
const worker = h.startWorker();
let sass = null;
async function compileSassAll() {
const start = process.hrtime();
log.info("init: compile styles")
sass = await h.compileSassAll(worker);
let output = await h.concatSass(sass);
await fs.writeFile("./resources/public/css/main.css", output);
const end = process.hrtime(start);
log.info("done: compile styles", `(${ppt(end)})`);
}
async function compileSass(path) {
const start = process.hrtime();
log.info("changed:", path);
const result = await h.compileSass(worker, path, {modules:true});
sass.index[result.outputPath] = result.css;
const output = h.concatSass(sass);
await fs.writeFile("./resources/public/css/main.css", output);
const end = process.hrtime(start);
log.info("done:", `(${ppt(end)})`);
}
await compileSassAll();
await h.copyAssets()
await h.compileSvgSprites()
await h.compileTemplates();
await h.compilePolyfills();
log.info("watch: scss src (~)")
h.watch("src", h.isSassFile, async function (path) {
if (path.includes("common")) {
await compileSassAll(path);
} else {
await compileSass(path);
}
});
log.info("watch: scss: resources (~)")
h.watch("resources/styles", h.isSassFile, async function (path) {
log.info("changed:", path);
await compileSassAll()
});
log.info("watch: templates (~)")
h.watch("resources/templates", null, async function (path) {
log.info("changed:", path);
await h.compileTemplates();
});
log.info("watch: assets (~)")
h.watch(["resources/images", "resources/fonts"], null, async function (path) {
log.info("changed:", path);
await h.compileSvgSprites();
await h.copyAssets();
await h.compileTemplates();
});
worker.terminate();

View file

@ -1471,6 +1471,13 @@ __metadata:
languageName: node
linkType: hard
"@bufbuild/protobuf@npm:^1.0.0":
version: 1.7.2
resolution: "@bufbuild/protobuf@npm:1.7.2"
checksum: 37a968b7d314c1f2e2b996bb287c72dbeaacd5bc0d92e2f706437a51c4e483ff85b97994428e252d6acf99bd7b16435471413ae3af1bd9b416d72ab3f0decd22
languageName: node
linkType: hard
"@colors/colors@npm:1.5.0":
version: 1.5.0
resolution: "@colors/colors@npm:1.5.0"
@ -5333,6 +5340,13 @@ __metadata:
languageName: node
linkType: hard
"buffer-builder@npm:^0.2.0":
version: 0.2.0
resolution: "buffer-builder@npm:0.2.0"
checksum: e50c3a379f4acaea75ade1ee3e8c07ed6d7c5dfc3f98adbcf0159bfe1a4ce8ca1fe3689e861fcdb3fcef0012ebd4345a6112a5b8a1185295452bb66d7b6dc8a1
languageName: node
linkType: hard
"buffer-crc32@npm:~0.2.3":
version: 0.2.13
resolution: "buffer-crc32@npm:0.2.13"
@ -6601,6 +6615,13 @@ __metadata:
languageName: node
linkType: hard
"dettle@npm:^1.0.1":
version: 1.0.1
resolution: "dettle@npm:1.0.1"
checksum: 116a101aff93b2e1d5e505adbe53c4b898d924bc16f12f5ac629055ed8a8a19c86f916b834b178b7bfb352dd601bbfe01e49ccd56144a5a2f780f4bd374ef112
languageName: node
linkType: hard
"diff-sequences@npm:^29.6.3":
version: 29.6.3
resolution: "diff-sequences@npm:29.6.3"
@ -7939,13 +7960,16 @@ __metadata:
marked: "npm:^12.0.0"
mkdirp: "npm:^3.0.1"
mousetrap: "npm:^1.6.5"
mustache: "npm:^4.2.0"
nodemon: "npm:^3.1.0"
npm-run-all: "npm:^4.1.5"
opentype.js: "npm:^1.3.4"
p-limit: "npm:^5.0.0"
postcss: "npm:^8.4.35"
postcss-clean: "npm:^1.2.2"
postcss-modules: "npm:^6.0.0"
prettier: "npm:^3.2.5"
pretty-time: "npm:^1.1.0"
prop-types: "npm:^15.8.1"
randomcolor: "npm:^0.6.2"
react: "npm:^18.2.0"
@ -7954,15 +7978,19 @@ __metadata:
rimraf: "npm:^5.0.5"
rxjs: "npm:8.0.0-alpha.14"
sass: "npm:^1.71.1"
sass-embedded: "npm:^1.71.1"
sax: "npm:^1.3.0"
shadow-cljs: "npm:2.27.4"
source-map-support: "npm:^0.5.21"
storybook: "npm:^7.6.17"
svg-sprite: "npm:^2.0.2"
tdigest: "npm:^0.1.2"
typescript: "npm:^5.3.3"
ua-parser-js: "npm:^1.0.37"
vite: "npm:^5.1.4"
vitest: "npm:^1.3.1"
watcher: "npm:^2.3.0"
workerpool: "npm:^9.1.0"
xregexp: "npm:^5.1.1"
languageName: unknown
linkType: soft
@ -12087,6 +12115,13 @@ __metadata:
languageName: node
linkType: hard
"pretty-time@npm:^1.1.0":
version: 1.1.0
resolution: "pretty-time@npm:1.1.0"
checksum: ba9d7af19cd43838fb2b147654990949575e400dc2cc24bf71ec4a6c4033a38ba8172b1014b597680c6d4d3c075e94648b2c13a7206c5f0c90b711c7388726f3
languageName: node
linkType: hard
"prettysize@npm:^2.0.0":
version: 2.0.0
resolution: "prettysize@npm:2.0.0"
@ -12122,6 +12157,13 @@ __metadata:
languageName: node
linkType: hard
"promise-make-naked@npm:^2.1.1":
version: 2.1.1
resolution: "promise-make-naked@npm:2.1.1"
checksum: 97bc0a3eeae59f75e8716d5f511edb4ed7558fa304f93407a7c9de3645a19135abfc87d4bca0b570619d3314fa87db67ea3463c4a5068c4bbe7f8889c6883f1d
languageName: node
linkType: hard
"promise-retry@npm:^2.0.1":
version: 2.0.1
resolution: "promise-retry@npm:2.0.1"
@ -13126,7 +13168,7 @@ __metadata:
languageName: node
linkType: hard
"rxjs@npm:^7.8.1":
"rxjs@npm:^7.4.0, rxjs@npm:^7.8.1":
version: 7.8.1
resolution: "rxjs@npm:7.8.1"
dependencies:
@ -13195,6 +13237,205 @@ __metadata:
languageName: node
linkType: hard
"sass-embedded-android-arm64@npm:1.71.1":
version: 1.71.1
resolution: "sass-embedded-android-arm64@npm:1.71.1"
bin:
sass: dart-sass/sass
conditions: os=android & cpu=arm64
languageName: node
linkType: hard
"sass-embedded-android-arm@npm:1.71.1":
version: 1.71.1
resolution: "sass-embedded-android-arm@npm:1.71.1"
bin:
sass: dart-sass/sass
conditions: os=android & cpu=arm
languageName: node
linkType: hard
"sass-embedded-android-ia32@npm:1.71.1":
version: 1.71.1
resolution: "sass-embedded-android-ia32@npm:1.71.1"
bin:
sass: dart-sass/sass
conditions: os=android & cpu=ia32
languageName: node
linkType: hard
"sass-embedded-android-x64@npm:1.71.1":
version: 1.71.1
resolution: "sass-embedded-android-x64@npm:1.71.1"
bin:
sass: dart-sass/sass
conditions: os=android & cpu=x64
languageName: node
linkType: hard
"sass-embedded-darwin-arm64@npm:1.71.1":
version: 1.71.1
resolution: "sass-embedded-darwin-arm64@npm:1.71.1"
bin:
sass: dart-sass/sass
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
"sass-embedded-darwin-x64@npm:1.71.1":
version: 1.71.1
resolution: "sass-embedded-darwin-x64@npm:1.71.1"
bin:
sass: dart-sass/sass
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
"sass-embedded-linux-arm64@npm:1.71.1":
version: 1.71.1
resolution: "sass-embedded-linux-arm64@npm:1.71.1"
bin:
sass: dart-sass/sass
conditions: os=linux & cpu=arm64
languageName: node
linkType: hard
"sass-embedded-linux-arm@npm:1.71.1":
version: 1.71.1
resolution: "sass-embedded-linux-arm@npm:1.71.1"
bin:
sass: dart-sass/sass
conditions: os=linux & cpu=arm
languageName: node
linkType: hard
"sass-embedded-linux-ia32@npm:1.71.1":
version: 1.71.1
resolution: "sass-embedded-linux-ia32@npm:1.71.1"
bin:
sass: dart-sass/sass
conditions: os=linux & cpu=ia32
languageName: node
linkType: hard
"sass-embedded-linux-musl-arm64@npm:1.71.1":
version: 1.71.1
resolution: "sass-embedded-linux-musl-arm64@npm:1.71.1"
conditions: os=linux & cpu=arm64
languageName: node
linkType: hard
"sass-embedded-linux-musl-arm@npm:1.71.1":
version: 1.71.1
resolution: "sass-embedded-linux-musl-arm@npm:1.71.1"
conditions: os=linux & cpu=arm
languageName: node
linkType: hard
"sass-embedded-linux-musl-ia32@npm:1.71.1":
version: 1.71.1
resolution: "sass-embedded-linux-musl-ia32@npm:1.71.1"
conditions: os=linux & cpu=ia32
languageName: node
linkType: hard
"sass-embedded-linux-musl-x64@npm:1.71.1":
version: 1.71.1
resolution: "sass-embedded-linux-musl-x64@npm:1.71.1"
conditions: os=linux & cpu=x64
languageName: node
linkType: hard
"sass-embedded-linux-x64@npm:1.71.1":
version: 1.71.1
resolution: "sass-embedded-linux-x64@npm:1.71.1"
bin:
sass: dart-sass/sass
conditions: os=linux & cpu=x64
languageName: node
linkType: hard
"sass-embedded-win32-ia32@npm:1.71.1":
version: 1.71.1
resolution: "sass-embedded-win32-ia32@npm:1.71.1"
bin:
sass: dart-sass/sass.bat
conditions: os=win32 & cpu=ia32
languageName: node
linkType: hard
"sass-embedded-win32-x64@npm:1.71.1":
version: 1.71.1
resolution: "sass-embedded-win32-x64@npm:1.71.1"
bin:
sass: dart-sass/sass.bat
conditions: os=win32 & (cpu=arm64 | cpu=x64)
languageName: node
linkType: hard
"sass-embedded@npm:^1.71.1":
version: 1.71.1
resolution: "sass-embedded@npm:1.71.1"
dependencies:
"@bufbuild/protobuf": "npm:^1.0.0"
buffer-builder: "npm:^0.2.0"
immutable: "npm:^4.0.0"
rxjs: "npm:^7.4.0"
sass-embedded-android-arm: "npm:1.71.1"
sass-embedded-android-arm64: "npm:1.71.1"
sass-embedded-android-ia32: "npm:1.71.1"
sass-embedded-android-x64: "npm:1.71.1"
sass-embedded-darwin-arm64: "npm:1.71.1"
sass-embedded-darwin-x64: "npm:1.71.1"
sass-embedded-linux-arm: "npm:1.71.1"
sass-embedded-linux-arm64: "npm:1.71.1"
sass-embedded-linux-ia32: "npm:1.71.1"
sass-embedded-linux-musl-arm: "npm:1.71.1"
sass-embedded-linux-musl-arm64: "npm:1.71.1"
sass-embedded-linux-musl-ia32: "npm:1.71.1"
sass-embedded-linux-musl-x64: "npm:1.71.1"
sass-embedded-linux-x64: "npm:1.71.1"
sass-embedded-win32-ia32: "npm:1.71.1"
sass-embedded-win32-x64: "npm:1.71.1"
supports-color: "npm:^8.1.1"
varint: "npm:^6.0.0"
dependenciesMeta:
sass-embedded-android-arm:
optional: true
sass-embedded-android-arm64:
optional: true
sass-embedded-android-ia32:
optional: true
sass-embedded-android-x64:
optional: true
sass-embedded-darwin-arm64:
optional: true
sass-embedded-darwin-x64:
optional: true
sass-embedded-linux-arm:
optional: true
sass-embedded-linux-arm64:
optional: true
sass-embedded-linux-ia32:
optional: true
sass-embedded-linux-musl-arm:
optional: true
sass-embedded-linux-musl-arm64:
optional: true
sass-embedded-linux-musl-ia32:
optional: true
sass-embedded-linux-musl-x64:
optional: true
sass-embedded-linux-x64:
optional: true
sass-embedded-win32-ia32:
optional: true
sass-embedded-win32-x64:
optional: true
checksum: 637b00398b92b88db6b6dc8906d1c6e42c6907cd26afbda05ff3cdc19360eb2efeeaa8591c995f14e05aa8a08314bf7af219a4cbe1172a95365ca6b442b799d5
languageName: node
linkType: hard
"sass@npm:^1.71.1":
version: 1.71.1
resolution: "sass@npm:1.71.1"
@ -14038,6 +14279,13 @@ __metadata:
languageName: node
linkType: hard
"stubborn-fs@npm:^1.2.5":
version: 1.2.5
resolution: "stubborn-fs@npm:1.2.5"
checksum: 0676befd9901d4dd4e162700fa0396f11d523998589cd6b61b06d1021db811dc4c1e6713869748c6cfa49d58beb9b6f0dc5b6aca6b075811b949e1602ce1e26f
languageName: node
linkType: hard
"supports-color@npm:^5.3.0, supports-color@npm:^5.4.0, supports-color@npm:^5.5.0":
version: 5.5.0
resolution: "supports-color@npm:5.5.0"
@ -14316,6 +14564,15 @@ __metadata:
languageName: node
linkType: hard
"tiny-readdir@npm:^2.2.0":
version: 2.4.0
resolution: "tiny-readdir@npm:2.4.0"
dependencies:
promise-make-naked: "npm:^2.1.1"
checksum: 0fd05eb677a9bf25f6ace33ad2eeaeb8555303321e18cd22c7a96391f099c1dd900d745738a1c6ba276540b1dc117f72fbbf60cc47bf1c7a73840745e3ea42f8
languageName: node
linkType: hard
"tinybench@npm:^2.5.1":
version: 2.5.1
resolution: "tinybench@npm:2.5.1"
@ -15071,6 +15328,13 @@ __metadata:
languageName: node
linkType: hard
"varint@npm:^6.0.0":
version: 6.0.0
resolution: "varint@npm:6.0.0"
checksum: 737fc37088a62ed3bd21466e318d21ca7ac4991d0f25546f518f017703be4ed0f9df1c5559f1dd533dddba4435a1b758fd9230e4772c1a930ef72b42f5c750fd
languageName: node
linkType: hard
"vary@npm:~1.1.2":
version: 1.1.2
resolution: "vary@npm:1.1.2"
@ -15311,6 +15575,17 @@ __metadata:
languageName: node
linkType: hard
"watcher@npm:^2.3.0":
version: 2.3.0
resolution: "watcher@npm:2.3.0"
dependencies:
dettle: "npm:^1.0.1"
stubborn-fs: "npm:^1.2.5"
tiny-readdir: "npm:^2.2.0"
checksum: 7b1e47321ddf96882ebee6f619211b085f98bc0c3bceb94a58938e8d8d209f83283b30b645bdae148e063c3bc165eeafd73e3a14bdb7c3bfe519bd7536172257
languageName: node
linkType: hard
"watchpack@npm:^2.2.0":
version: 2.4.0
resolution: "watchpack@npm:2.4.0"
@ -15521,6 +15796,13 @@ __metadata:
languageName: node
linkType: hard
"workerpool@npm:^9.1.0":
version: 9.1.0
resolution: "workerpool@npm:9.1.0"
checksum: 32d0807962be58a98ec22f5630be4a90f779f5faab06d5b4f000d32c11c8d5feb66be9bc5c73fdc49c91519e391db55c9e2e63392854b3df945744b2436a7efd
languageName: node
linkType: hard
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0, wrap-ansi@npm:^7.0.0":
version: 7.0.0
resolution: "wrap-ansi@npm:7.0.0"