diff --git a/docusaurus.config.ts b/docusaurus.config.ts index c3b4b6dd1..a737dc21d 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -1,8 +1,8 @@ require('dotenv').config(); +import logger from '@docusaurus/logger'; import type { EditThisPageOption, ShowEditThisPage, - SiteConfig, TdevConfig } from '@tdev/siteConfig/siteConfig'; import { themes as prismThemes } from 'prism-react-renderer'; @@ -24,6 +24,7 @@ import { taskStateOverview } from './src/siteConfig/navbarItems'; import { applyTransformers } from './src/siteConfig/transformers'; +import { withSiteConfig } from './src/siteConfig/withSiteConfig'; import { sassPluginConfig, dynamicRouterPluginConfig, @@ -37,24 +38,10 @@ import path from 'path'; import { recommendedBeforeDefaultRemarkPlugins, recommendedRehypePlugins, - recommendedRemarkPlugins + recommendedRemarkPlugins, } from './src/siteConfig/markdownPluginConfigs'; import { remarkPdfPluginConfig } from '@tdev/remark-pdf'; import { GlobExcludeDefault } from '@docusaurus/utils'; -import extractPackageDocs from './src/siteConfig/extractPackageDocs'; - -const withSiteConfig = async (): Promise => { - if (process.env.SITE_CONFIG_PATH) { - console.log(`Using site config from ${process.env.SITE_CONFIG_PATH}`); - const pathToConfig = path.resolve(process.cwd(), process.env.SITE_CONFIG_PATH); - const getConfig = await import(pathToConfig).then((mod) => mod.default); - return getConfig(); - } else { - console.log(`Using site config from default './siteConfig'`); - const getConfig = await import('./siteConfig').then((mod) => mod.default); - return getConfig(); - } -}; const BUILD_LOCATION = __dirname; const GIT_COMMIT_SHA = process.env.GITHUB_SHA || Math.random().toString(36).substring(7); @@ -80,6 +67,8 @@ const docusaurusConfig = withSiteConfig().then(async (siteConfig) => { const DOCS_PATH = useTdevContentPath(siteConfig, 'docs'); const BLOG_PATH = useTdevContentPath(siteConfig, 'blog'); + //await packageDocsSync('packages', `${DOCS_PATH}/packages`); + const BEFORE_DEFAULT_REMARK_PLUGINS = siteConfig.beforeDefaultRemarkPlugins ?? recommendedBeforeDefaultRemarkPlugins; @@ -242,6 +231,12 @@ const docusaurusConfig = withSiteConfig().then(async (siteConfig) => { if (needsRewrite) { await fs.writeFile(params.filePath, matter.stringify(params.fileContent, result.frontMatter), { encoding: 'utf-8' + }).catch((e) => { + if (e.code === 'EACCES') { + const parts = params.filePath.split(path.sep).slice(-3); + logger.warn(`Could not rewrite frontmatter due to insufficient file permissions. Did you create a new file in a subfolder of ./packages/${parts.slice(0, 2).join('/')} ?`); + logger.info(`Make sure to add the following frontmatter manually to the head of "${parts.join(path.sep)}":\n\n${matter.stringify('', result.frontMatter)}`); + } }); } } @@ -272,10 +267,6 @@ const docusaurusConfig = withSiteConfig().then(async (siteConfig) => { beforeDefaultRemarkPlugins: BEFORE_DEFAULT_REMARK_PLUGINS, ...DEFAULT_ADMONITION_CONFIG, exclude: [...new Set([...GlobExcludeDefault, '**/node_modules/**'])], - async sidebarItemsGenerator({defaultSidebarItemsGenerator, ...args}) { - const sidebarItems = await defaultSidebarItemsGenerator(args); - return extractPackageDocs(sidebarItems); - }, ...(siteConfig.docs || {}) } : false, diff --git a/package.json b/package.json index e760ff5aa..a4d51822c 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "private": true, "scripts": { "docusaurus": "docusaurus", - "start": "docusaurus start", + "start": "concurrently --raw --kill-others 'docusaurus start' 'ts-node updateSync/packageDocsSync/watch.ts --src packages --dest tdev-website/docs/packages'", + "prebuild": "ts-node updateSync/packageDocsSync/preBuild.ts --src packages --dest tdev-website/docs/packages", "build": "docusaurus build", "swizzle": "docusaurus swizzle", "deploy": "docusaurus deploy", @@ -65,6 +66,7 @@ "mdast-util-math": "^3.0.0", "micromark-extension-math": "^3.1.0", "micromatch": "^4.0.8", + "minimist": "^1.2.8", "mobx": "^6.15.0", "mobx-react-lite": "^4.1.1", "mobx-utils": "^6.1.1", @@ -97,12 +99,14 @@ "@types/fs-extra": "^11.0.4", "@types/js-yaml": "^4.0.9", "@types/micromatch": "^4.0.9", + "@types/minimist": "^1.2.5", "@types/react-dom": "^19.0.3", "@types/react-katex": "^3.0.4", "@types/svg-parser": "^2.0.6", "@types/uuid": "^10.0.0", "@types/wicg-file-system-access": "^2023.10.6", "@vitest/coverage-v8": "^2.0.5", + "concurrently": "^9.2.1", "fs-extra": "^11.2.0", "prettier": "^3.3.2", "remark": "^15.0.1", @@ -134,4 +138,4 @@ "engines": { "node": ">=22.15" } -} \ No newline at end of file +} diff --git a/packages/README.mdx b/packages/README.mdx deleted file mode 100644 index f68651aa2..000000000 --- a/packages/README.mdx +++ /dev/null @@ -1,5 +0,0 @@ ---- -page_id: a67a8811-3aac-47de-9265-68583cd9f80e ---- - -# Packages \ No newline at end of file diff --git a/src/siteConfig/extractPackageDocs.ts b/src/siteConfig/extractPackageDocs.ts deleted file mode 100644 index f427d413e..000000000 --- a/src/siteConfig/extractPackageDocs.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { - NormalizedSidebar, - NormalizedSidebarItem -} from '@docusaurus/plugin-content-docs/src/sidebars/types.js'; - -const extractPackageDocs = (items: NormalizedSidebar): NormalizedSidebar => { - // Reverse items in categories - const result = items.map((item) => { - if (item.type !== 'category' || item.key !== 'packages-docs') { - return item; - } - const itemCategory = { - ...item, - items: item.items.slice().flatMap((subItem) => { - if (subItem.type !== 'category') { - return [subItem]; - } - const newItems = subItem.items.reduce((acc, subSubItem) => { - // if a doc is found as a direct child of the category, keep it - if (subSubItem.type !== 'category') { - return [...acc, subSubItem]; - } - // if the sub-sub-category is empty and has a link to a doc, keep the link - if (subSubItem.items.length === 0 && subSubItem.link?.type === 'doc') { - return [...acc, subSubItem]; - } - // otherwise, inline the items of the sub-sub-category - if (subSubItem.items.length === 1 && !subSubItem.link) { - return [...acc, ...subSubItem.items]; - } - return [...acc, subSubItem]; - }, [] as NormalizedSidebarItem[]); - return { - ...subItem, - items: newItems - } as NormalizedSidebarItem; - }) - }; - return itemCategory; - }); - return result; -}; - -export default extractPackageDocs; diff --git a/src/siteConfig/withSiteConfig.ts b/src/siteConfig/withSiteConfig.ts new file mode 100644 index 000000000..7885bd33b --- /dev/null +++ b/src/siteConfig/withSiteConfig.ts @@ -0,0 +1,16 @@ +import type { SiteConfig } from './siteConfig'; +import path from 'path'; + +export const withSiteConfig = async (): Promise => { + if (process.env.SITE_CONFIG_PATH) { + console.log(`Using site config from ${process.env.SITE_CONFIG_PATH}`); + const pathToConfig = path.resolve(process.cwd(), process.env.SITE_CONFIG_PATH); + const getConfig = await import(pathToConfig).then((mod) => mod.default); + return getConfig(); + } else { + console.log(`Using site config from default './siteConfig'`); + const pathToConfig = path.resolve(process.cwd(), 'siteConfig'); + const getConfig = await import(pathToConfig).then((mod) => mod.default); + return getConfig(); + } +}; diff --git a/tdev-website/docs/packages/.gitignore b/tdev-website/docs/packages/.gitignore new file mode 100644 index 000000000..d6b7ef32c --- /dev/null +++ b/tdev-website/docs/packages/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/updateSync/packageDocsSync/actions.ts b/updateSync/packageDocsSync/actions.ts new file mode 100644 index 000000000..00d8eb6f2 --- /dev/null +++ b/updateSync/packageDocsSync/actions.ts @@ -0,0 +1,273 @@ +import path from 'path'; +import fs from 'fs/promises'; +import yaml from 'js-yaml'; +import { debounce } from 'es-toolkit/compat'; + +interface TdevPackageConfig { + path: string; + docs: { + org: string; + package: string; + path: string; + include?: string[]; + exclude?: string[]; + }; +} + +const TDEV_PACKAGE_CONFIG_YML = 'tdevPackage.config.yml' as const; +const DEFAULT_DOCS_CONFIG: Omit = { + path: 'docs' +}; +const CWD = process.cwd(); + +const DEFAULT_README_CONFIG: Omit = { + path: '.', + include: [ + 'README.md', + 'README.mdx', + '_category_.yml', + '_category_.json', + 'assets/**', + 'images/**', + 'img/**' + ] +}; + +interface PackageInfo { + packageDir: string; + org: string; + package: string; + relativeSubPath?: string; +} + +const resolveDir = (pkgPath: string, ...parts: string[]): string => { + if (pkgPath.startsWith(CWD)) { + return path.resolve(pkgPath, ...parts); + } + return path.resolve(CWD, pkgPath, ...parts); +}; + +const CATEGORY_MATCHER = /^_category_\.(json|ya?ml)$/; +export const categoryFileLocation = (filePath: string, packageDir: string): string | null => { + if (!filePath.startsWith(packageDir)) { + return null; + } + const relPath = path.relative(packageDir, filePath); + const parts = relPath.split(path.sep); + if (parts.length === 1 && CATEGORY_MATCHER.test(parts[0])) { + return ''; + } + if (parts.length === 2 && CATEGORY_MATCHER.test(parts[1])) { + return parts[0]; + } + return null; +}; + +export const packageInfo = (filePath: string, packageDir: string): PackageInfo | null => { + if (!filePath.startsWith(packageDir)) { + return null; + } + const relPath = path.relative(packageDir, filePath); + const parts = relPath.split(path.sep); + if (parts.length < 3) { + return null; + } + const pkgInfo: PackageInfo = { + packageDir, + org: parts[0], + package: parts[1] + }; + const relativeSubPath = parts.slice(2).join(path.sep); + if (relativeSubPath.length > 0) { + pkgInfo.relativeSubPath = relativeSubPath; + } + return pkgInfo; +}; + +export const syncCategoryFile = async (srcFolder: string, destFolder: string) => { + for (const ext of ['.json', '.yaml', '.yml']) { + const categoryFileSrc = path.join(srcFolder, `_category_${ext}`); + try { + const stat = await fs.stat(categoryFileSrc); + if (stat.isFile()) { + const categoryFileDest = path.join(destFolder, `_category_${ext}`); + await fs.mkdir(path.dirname(categoryFileDest), { recursive: true }); + await fs.copyFile(categoryFileSrc, categoryFileDest); + return `✅ Copied ${destFolder}/_category_${ext}.`; + } + } catch {} + } + return null; +}; + +export const syncDocsFolder = async (pkgConfig: TdevPackageConfig, packageDocsDir: string) => { + const { org, package: packageName, path: docsPath } = pkgConfig.docs; + const srcPath = resolveDir(pkgConfig.path, docsPath); + const destPackagePath = resolveDir(packageDocsDir, org, packageName); + await fs.mkdir(destPackagePath, { recursive: true }); + const rsyncArgs = ['-avq', '--delete', '--chmod=Fa-w']; + if (pkgConfig.docs.include && pkgConfig.docs.include.length > 0) { + pkgConfig.docs.include.forEach((inc) => { + rsyncArgs.push('--include', inc); + }); + rsyncArgs.push('--exclude', '*'); + } + if (pkgConfig.docs.exclude && pkgConfig.docs.exclude.length > 0) { + pkgConfig.docs.exclude.forEach((exc) => { + rsyncArgs.push('--exclude', exc); + }); + } + rsyncArgs.push(`${srcPath}/`, destPackagePath); + const { spawn } = await import('child_process'); + return new Promise((resolve, reject) => { + const rsync = spawn('rsync', rsyncArgs, { stdio: 'inherit' }); + rsync.on('close', (code) => { + if (code === 0) { + resolve(`✅ ${pkgConfig.docs.org}/${pkgConfig.docs.package} docs synced.`); + } else { + console.error(`rsync failed with exit code ${code}`); + reject(new Error(`rsync process exited with code ${code}`)); + } + }); + }); +}; + +const getPackageDocsConfig = async ( + packagesDir: string, + orgName: string, + packageName: string +): Promise => { + const packagePath = path.join(packagesDir, orgName, packageName); + + // Heuristic 1: tdevPackage.config.yml + const configYml = path.join(packagePath, TDEV_PACKAGE_CONFIG_YML); + try { + await fs.access(configYml); + const raw = await fs.readFile(configYml, 'utf8'); + const config: any = yaml.load(raw) || {}; + return { + path: packagePath, + docs: { + org: orgName, + package: packageName, + ...config.docs + } + }; + } catch {} + + // Heuristic 2: docs folder + const docsDir = path.join(packagePath, 'docs'); + try { + const stat = await fs.stat(docsDir); + if (stat.isDirectory()) { + return { + path: packagePath, + docs: { + ...DEFAULT_DOCS_CONFIG, + org: orgName, + package: packageName + } + }; + } + } catch {} + + // Heuristic 3: README.mdx? at root + for (const file of ['README.mdx', 'README.md']) { + const readmePath = path.join(packagePath, file); + try { + const stat = await fs.stat(readmePath); + if (stat.isFile()) { + return { + path: packagePath, + docs: { + ...DEFAULT_README_CONFIG, + org: orgName, + package: packageName + } + }; + } + } catch {} + } + return null; +}; + +export const getPackageDocsConfigs = async (packagesDir: string): Promise => { + const orgDirs = await fs.readdir(packagesDir, { withFileTypes: true }); + const allConfigs: TdevPackageConfig[] = []; + + for (const orgDir of orgDirs) { + if (!orgDir.isDirectory()) { + continue; + } + const orgPath = path.join(packagesDir, orgDir.name); + const packageDirs = await fs.readdir(orgPath, { withFileTypes: true }); + + for (const packageDirEnt of packageDirs) { + if (!packageDirEnt.isDirectory()) { + continue; + } + const pkgConfig = await getPackageDocsConfig(packagesDir, orgDir.name, packageDirEnt.name); + if (pkgConfig) { + allConfigs.push(pkgConfig); + } + } + } + + return allConfigs; +}; + +export const getDebouncedSyncer = async (packageDir: string, destDir: string) => { + const syncQueue = new Set(); + const PackageConfigCache: Map = new Map(); + getPackageDocsConfigs(packageDir).then((configs) => { + for (const cfg of configs) { + const pkgKey = `${cfg.docs.org}/${cfg.docs.package}`; + PackageConfigCache.set(pkgKey, cfg); + } + }); + + const setPackageConfig = async (pkgKey: string, newConfig?: TdevPackageConfig) => { + if (!newConfig) { + return false; + } + const prevConfig = PackageConfigCache.get(pkgKey); + if (prevConfig) { + const prevDocsPath = resolveDir(destDir, prevConfig.docs.org, prevConfig.docs.package); + const currentDocsPath = resolveDir(destDir, newConfig.docs.org, newConfig.docs.package); + if (prevDocsPath !== currentDocsPath) { + fs.rm(prevDocsPath, { recursive: true, force: true }).catch(() => {}); + } + } + PackageConfigCache.set(pkgKey, newConfig); + return true; + }; + + const syncDebounced = debounce(async () => { + const syncTasks: Promise[] = []; + for (const pkgInfo of syncQueue) { + if (!pkgInfo) { + continue; + } + const pkgKey = `${pkgInfo.org}/${pkgInfo.package}`; + if (pkgInfo.relativeSubPath === TDEV_PACKAGE_CONFIG_YML) { + const res = getPackageDocsConfig(packageDir, pkgInfo.org, pkgInfo.package).then( + (newConfig) => { + if (setPackageConfig(pkgKey, newConfig)) { + return syncDocsFolder(newConfig, destDir); + } + return Promise.resolve(`ℹ️ ${pkgKey} docs config unchanged.`); + } + ); + syncTasks.push(res); + } else { + const pkgConfig = PackageConfigCache.get(pkgKey); + if (pkgConfig) { + syncTasks.push(syncDocsFolder(pkgConfig, destDir)); + } + } + } + syncQueue.clear(); + return Promise.all(syncTasks); + }, 300); + return { syncQueue, syncDebounced }; +}; diff --git a/updateSync/packageDocsSync/index.ts b/updateSync/packageDocsSync/index.ts new file mode 100644 index 000000000..bb675461f --- /dev/null +++ b/updateSync/packageDocsSync/index.ts @@ -0,0 +1,33 @@ +import fs from 'fs/promises'; +import { getPackageDocsConfigs, syncCategoryFile, syncDocsFolder } from './actions'; +import path from 'path'; + +const packageDocsSync = async (packageDir: string, destDir: string) => { + const srcPath = path.resolve(process.cwd(), packageDir); + const data = await getPackageDocsConfigs(srcPath); + // create the dest dir if it doesn't exist + const destPath = path.resolve(process.cwd(), destDir); + await fs.rm(destPath, { recursive: true, force: true }); + await fs.mkdir(destPath, { recursive: true }); + /** + * add .gitignore to destPath to ignore all files + */ + const gitignorePath = path.join(destPath, '.gitignore'); + const gitignoreContent = '*\n!.gitignore\n'; + await fs.writeFile(gitignorePath, gitignoreContent, 'utf8'); + const orgs = [...new Set(data.map((cfg) => cfg.docs.org))]; + const result = await Promise.all([ + ...data.map(async (pkgConfig) => { + return syncDocsFolder(pkgConfig, destPath); + }), + ...orgs.map(async (org) => { + const orgSrc = path.join(srcPath, org); + return syncCategoryFile(orgSrc, path.join(destPath, org)); + }), + syncCategoryFile(srcPath, destPath) + ]); + console.log(result.filter(Boolean).join('\n')); + return result; +}; + +export default packageDocsSync; diff --git a/updateSync/packageDocsSync/preBuild.ts b/updateSync/packageDocsSync/preBuild.ts new file mode 100644 index 000000000..a938dc7f3 --- /dev/null +++ b/updateSync/packageDocsSync/preBuild.ts @@ -0,0 +1,25 @@ +import path from 'path'; +import minimist from 'minimist'; +import packageDocsSync from '.'; +const argv = minimist(process.argv.slice(2), { + string: ['src', 'dest'], + alias: { src: 'packages', dest: 'out' }, + default: { + src: 'packages' + } +}); +const CWD = process.cwd(); +const { src, dest } = argv; + +const PACKAGES_DIR = path.resolve(CWD, src); +const DEST_ROOT = path.resolve(CWD, dest); + +const main = async () => { + await packageDocsSync(PACKAGES_DIR, DEST_ROOT); + console.log('✅ Pre-build docs sync completed.'); +}; + +main().catch((err) => { + console.error('Error in docs watcher:', err); + process.exit(1); +}); diff --git a/updateSync/packageDocsSync/watch.ts b/updateSync/packageDocsSync/watch.ts new file mode 100644 index 000000000..c9a9faef3 --- /dev/null +++ b/updateSync/packageDocsSync/watch.ts @@ -0,0 +1,49 @@ +import chokidar from 'chokidar'; +import minimist from 'minimist'; +import path from 'path'; +import { getDebouncedSyncer, categoryFileLocation, packageInfo, syncCategoryFile } from './actions'; +import packageDocsSync from '.'; + +const argv = minimist(process.argv.slice(2), { + string: ['src', 'dest'], + alias: { src: 'packages', dest: 'out' }, + default: { + src: 'packages' + } +}); + +const PACKAGES_DIR = path.resolve(process.cwd(), argv.src); +const DEST_ROOT = path.resolve(process.cwd(), argv.dest); + +const watcher = chokidar.watch(PACKAGES_DIR, { ignoreInitial: true, persistent: true }); + +const main = async () => { + const { syncQueue, syncDebounced } = await getDebouncedSyncer(PACKAGES_DIR, DEST_ROOT); + const NODE_MODULES_TEST = /node_modules/; + await packageDocsSync(PACKAGES_DIR, DEST_ROOT); + + watcher + .on('all', async (_event, filePath) => { + if (NODE_MODULES_TEST.test(filePath)) { + return null; + } + const pkgInfo = packageInfo(filePath, PACKAGES_DIR); + if (pkgInfo) { + syncQueue.add(pkgInfo); + syncDebounced(); + } else { + const location = categoryFileLocation(filePath, PACKAGES_DIR); + if (location !== null) { + return syncCategoryFile(PACKAGES_DIR, path.join(DEST_ROOT, location)); + } + } + }) + .on('ready', () => { + console.log('Watching for docs changes in packages...'); + }); +}; + +main().catch((err) => { + console.error('Error in docs watcher:', err); + process.exit(1); +}); diff --git a/yarn.lock b/yarn.lock index 1b74813fd..7582f8aaa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5897,6 +5897,11 @@ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== +"@types/minimist@^1.2.5": + version "1.2.5" + resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.5.tgz#ec10755e871497bcd83efe927e43ec46e8c0747e" + integrity sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag== + "@types/ms@*": version "2.1.0" resolved "https://registry.yarnpkg.com/@types/ms/-/ms-2.1.0.tgz#052aa67a48eccc4309d7f0191b7e41434b90bb78" @@ -7134,6 +7139,14 @@ chainsaw@~0.1.0: dependencies: traverse ">=0.3.0 <0.4" +chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -7143,14 +7156,6 @@ chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0, chalk@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - chalk@^5.0.1, chalk@^5.2.0: version "5.6.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.6.2.tgz#b1238b6e23ea337af71c7f8a295db5af0c158aea" @@ -7303,6 +7308,15 @@ cli-table3@^0.6.3: optionalDependencies: "@colors/colors" "1.5.0" +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + clone-deep@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" @@ -7466,6 +7480,18 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== +concurrently@^9.2.1: + version "9.2.1" + resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-9.2.1.tgz#248ea21b95754947be2dad9c3e4b60f18ca4e44f" + integrity sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng== + dependencies: + chalk "4.1.2" + rxjs "7.8.2" + shell-quote "1.8.3" + supports-color "8.1.1" + tree-kill "1.2.2" + yargs "17.7.2" + confbox@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.8.tgz#820d73d3b3c82d9bd910652c5d4d599ef8ff8b06" @@ -9379,6 +9405,11 @@ gensync@^1.0.0-beta.2: resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" @@ -12097,7 +12128,7 @@ minimatch@^9.0.4: dependencies: brace-expansion "^2.0.1" -minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6: +minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6, minimist@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -14122,6 +14153,11 @@ repeat-string@^1.0.0: resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + require-from-string@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" @@ -14278,6 +14314,13 @@ rw@1: resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4" integrity sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ== +rxjs@7.8.2: + version "7.8.2" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.2.tgz#955bc473ed8af11a002a2be52071bf475638607b" + integrity sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA== + dependencies: + tslib "^2.1.0" + sade@^1.7.3: version "1.8.1" resolved "https://registry.yarnpkg.com/sade/-/sade-1.8.1.tgz#0a78e81d658d394887be57d2a409bf703a3b2701" @@ -14524,7 +14567,7 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shell-quote@^1.8.3: +shell-quote@1.8.3, shell-quote@^1.8.3: version "1.8.3" resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.3.tgz#55e40ef33cf5c689902353a3d8cd1a6725f08b4b" integrity sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw== @@ -14815,7 +14858,7 @@ strict-event-emitter@^0.4.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^4.1.0, string-width@^4.2.0: +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -14942,6 +14985,13 @@ stylis@^4.1.3, stylis@^4.3.6: resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.6.tgz#7c7b97191cb4f195f03ecab7d52f7902ed378320" integrity sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ== +supports-color@8.1.1, supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -14956,13 +15006,6 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -supports-color@^8.0.0: - version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" @@ -15172,6 +15215,11 @@ tree-dump@^1.0.3, tree-dump@^1.1.0: resolved "https://registry.yarnpkg.com/tree-dump/-/tree-dump-1.1.0.tgz#ab29129169dc46004414f5a9d4a3c6e89f13e8a4" integrity sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA== +tree-kill@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + trim-lines@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/trim-lines/-/trim-lines-3.0.1.tgz#d802e332a07df861c48802c04321017b1bd87338" @@ -16049,6 +16097,11 @@ xmlhttprequest-ssl@~2.1.1: resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz#e9e8023b3f29ef34b97a859f584c5e6c61418e23" integrity sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ== +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + yallist@^3.0.2: version "3.1.1" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" @@ -16059,6 +16112,24 @@ yaml@^1.10.0: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@17.7.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"