mirror of
https://github.com/anomalyco/opentui.git
synced 2026-09-19 01:26:03 +08:00
Make mono repo (#22)
This commit is contained in:
@@ -1,243 +0,0 @@
|
||||
import { spawnSync } from "node:child_process"
|
||||
import { copyFileSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs"
|
||||
import { dirname, join, resolve } from "path"
|
||||
import { fileURLToPath } from "url"
|
||||
import process from "process"
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = dirname(__filename)
|
||||
const rootDir = resolve(__dirname, "..")
|
||||
const licensePath = join(rootDir, "LICENSE")
|
||||
const packageJson = JSON.parse(readFileSync(join(rootDir, "package.json"), "utf8"))
|
||||
|
||||
const args = process.argv.slice(2)
|
||||
const buildLib = args.find((arg) => arg === "--lib")
|
||||
const buildNative = args.find((arg) => arg === "--native")
|
||||
const isDev = args.includes("--dev")
|
||||
|
||||
const variants = [
|
||||
{ platform: "darwin", arch: "x64" },
|
||||
{ platform: "darwin", arch: "arm64" },
|
||||
{ platform: "linux", arch: "x64" },
|
||||
{ platform: "linux", arch: "arm64" },
|
||||
{ platform: "win32", arch: "x64" },
|
||||
{ platform: "win32", arch: "arm64" },
|
||||
]
|
||||
|
||||
if (!buildLib && !buildNative) {
|
||||
console.error("Error: Please specify --lib, --native, or both")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const getZigTarget = (platform, arch) => {
|
||||
const platformMap = { darwin: "macos", win32: "windows", linux: "linux" }
|
||||
const archMap = { x64: "x86_64", arm64: "aarch64" }
|
||||
return `${archMap[arch] ?? arch}-${platformMap[platform] ?? platform}`
|
||||
}
|
||||
|
||||
const replaceLinks = (text) => {
|
||||
return packageJson.homepage
|
||||
? text.replace(
|
||||
/(\[.*?\]\()(\.\/.*?\))/g,
|
||||
(_, p1, p2) => `${p1}${packageJson.homepage}/blob/HEAD/${p2.replace("./", "")}`,
|
||||
)
|
||||
: text
|
||||
}
|
||||
|
||||
const requiredFields = ["name", "version", "license", "repository", "description"]
|
||||
const missingRequired = requiredFields.filter((field) => !packageJson[field])
|
||||
if (missingRequired.length > 0) {
|
||||
console.error(`Error: Missing required fields in package.json: ${missingRequired.join(", ")}`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if (buildNative) {
|
||||
console.log(`Building native ${isDev ? "dev" : "prod"} binaries...`)
|
||||
|
||||
const zigBuild = spawnSync("zig", ["build", `-Doptimize=${isDev ? "Debug" : "ReleaseFast"}`], {
|
||||
cwd: join(rootDir, "src", "zig"),
|
||||
stdio: "inherit",
|
||||
})
|
||||
|
||||
if (zigBuild.error) {
|
||||
console.error("Error: Zig is not installed or not in PATH")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if (zigBuild.status !== 0) {
|
||||
console.error("Error: Zig build failed")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
for (const { platform, arch } of variants) {
|
||||
const nativeName = `${packageJson.name}-${platform}-${arch}`
|
||||
const nativeDir = join(rootDir, "node_modules", nativeName)
|
||||
const libDir = join(rootDir, "src", "zig", "lib", getZigTarget(platform, arch))
|
||||
|
||||
rmSync(nativeDir, { recursive: true, force: true })
|
||||
mkdirSync(nativeDir, { recursive: true })
|
||||
|
||||
for (const name of ["libopentui", "opentui"]) {
|
||||
for (const ext of [".so", ".dll", ".dylib"]) {
|
||||
const src = join(libDir, `${name}${ext}`)
|
||||
if (existsSync(src)) copyFileSync(src, join(nativeDir, `${name}${ext}`))
|
||||
}
|
||||
}
|
||||
|
||||
writeFileSync(
|
||||
join(nativeDir, "package.json"),
|
||||
JSON.stringify(
|
||||
{
|
||||
name: nativeName,
|
||||
version: packageJson.version,
|
||||
description: `Prebuilt ${platform}-${arch} binaries for ${packageJson.name}`,
|
||||
license: packageJson.license,
|
||||
author: packageJson.author,
|
||||
homepage: packageJson.homepage,
|
||||
repository: packageJson.repository,
|
||||
bugs: packageJson.bugs,
|
||||
keywords: [...(packageJson.keywords ?? []), "prebuild", "prebuilt"],
|
||||
os: [platform],
|
||||
cpu: [arch],
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
)
|
||||
|
||||
writeFileSync(
|
||||
join(nativeDir, "README.md"),
|
||||
replaceLinks(`## ${nativeName}\n\n> Prebuilt ${platform}-${arch} binaries for \`${packageJson.name}\`.`),
|
||||
)
|
||||
|
||||
if (existsSync(licensePath)) copyFileSync(licensePath, join(nativeDir, "LICENSE"))
|
||||
console.log("Built:", nativeName)
|
||||
}
|
||||
}
|
||||
|
||||
if (buildLib) {
|
||||
console.log("Building library...")
|
||||
|
||||
const distDir = join(rootDir, "dist")
|
||||
rmSync(distDir, { recursive: true, force: true })
|
||||
mkdirSync(distDir, { recursive: true })
|
||||
|
||||
const externalDeps = [
|
||||
...Object.keys(packageJson.optionalDependencies || {}),
|
||||
...Object.keys(packageJson.peerDependencies || {}),
|
||||
]
|
||||
|
||||
// Build main entry point
|
||||
spawnSync(
|
||||
"bun",
|
||||
[
|
||||
"build",
|
||||
"--target=bun",
|
||||
"--outdir=dist",
|
||||
...externalDeps.flatMap((dep) => ["--external", dep]),
|
||||
packageJson.module,
|
||||
],
|
||||
{
|
||||
cwd: rootDir,
|
||||
stdio: "inherit",
|
||||
},
|
||||
)
|
||||
|
||||
// Build additional entry points
|
||||
const entryPoints = ["src/3d.ts"]
|
||||
for (const entryPoint of entryPoints) {
|
||||
spawnSync(
|
||||
"bun",
|
||||
["build", "--target=bun", "--outdir=dist", ...externalDeps.flatMap((dep) => ["--external", dep]), entryPoint],
|
||||
{
|
||||
cwd: rootDir,
|
||||
stdio: "inherit",
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
console.log("Generating TypeScript declarations...")
|
||||
|
||||
const tsconfigBuildPath = join(rootDir, "tsconfig.build.json")
|
||||
const tsconfigBuild = {
|
||||
extends: "./tsconfig.json",
|
||||
compilerOptions: {
|
||||
declaration: true,
|
||||
emitDeclarationOnly: true,
|
||||
outDir: "./dist",
|
||||
noEmit: false,
|
||||
rootDir: "./src",
|
||||
types: ["bun", "node", "three"],
|
||||
skipLibCheck: true,
|
||||
},
|
||||
include: ["src/**/*"],
|
||||
exclude: ["**/*.test.ts", "**/*.spec.ts", "src/examples/**/*", "src/benchmark/**/*", "src/zig/**/*"],
|
||||
}
|
||||
|
||||
writeFileSync(tsconfigBuildPath, JSON.stringify(tsconfigBuild, null, 2))
|
||||
|
||||
const tscResult = spawnSync("npx", ["tsc", "-p", tsconfigBuildPath], {
|
||||
cwd: rootDir,
|
||||
stdio: "inherit",
|
||||
})
|
||||
|
||||
rmSync(tsconfigBuildPath, { force: true })
|
||||
|
||||
if (tscResult.status !== 0) {
|
||||
console.warn("Warning: TypeScript declaration generation failed")
|
||||
} else {
|
||||
console.log("TypeScript declarations generated")
|
||||
}
|
||||
|
||||
// Configure exports for multiple entry points
|
||||
const exports = {
|
||||
".": {
|
||||
import: "./index.js",
|
||||
require: "./index.js",
|
||||
types: "./index.d.ts",
|
||||
},
|
||||
"./3d": {
|
||||
import: "./3d.js",
|
||||
require: "./3d.js",
|
||||
types: "./3d.d.ts",
|
||||
},
|
||||
}
|
||||
|
||||
const optionalDeps = Object.fromEntries(
|
||||
variants.map(({ platform, arch }) => [`${packageJson.name}-${platform}-${arch}`, `^${packageJson.version}`]),
|
||||
)
|
||||
|
||||
writeFileSync(
|
||||
join(distDir, "package.json"),
|
||||
JSON.stringify(
|
||||
{
|
||||
name: packageJson.name,
|
||||
module: "index.js",
|
||||
main: "index.js",
|
||||
types: "index.d.ts",
|
||||
type: packageJson.type,
|
||||
version: packageJson.version,
|
||||
description: packageJson.description,
|
||||
keywords: packageJson.keywords,
|
||||
license: packageJson.license,
|
||||
author: packageJson.author,
|
||||
homepage: packageJson.homepage,
|
||||
repository: packageJson.repository,
|
||||
bugs: packageJson.bugs,
|
||||
exports,
|
||||
dependencies: packageJson.dependencies,
|
||||
optionalDependencies: {
|
||||
...packageJson.optionalDependencies,
|
||||
...optionalDeps,
|
||||
},
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
)
|
||||
|
||||
writeFileSync(join(distDir, "README.md"), replaceLinks(readFileSync(join(rootDir, "README.md"), "utf8")))
|
||||
if (existsSync(licensePath)) copyFileSync(licensePath, join(distDir, "LICENSE"))
|
||||
|
||||
console.log("Library built at:", distDir)
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
import { spawnSync } from "node:child_process"
|
||||
import { existsSync, mkdirSync, readFileSync, rmSync, statSync } from "node:fs"
|
||||
import { dirname, join, resolve } from "node:path"
|
||||
import process from "node:process"
|
||||
import { fileURLToPath } from "node:url"
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = dirname(__filename)
|
||||
const rootDir = resolve(__dirname, "..")
|
||||
const packedDir = join(rootDir, "packed")
|
||||
|
||||
const packageJson = JSON.parse(readFileSync(join(rootDir, "package.json"), "utf8"))
|
||||
|
||||
const args = process.argv.slice(2)
|
||||
const skipBuild = args.includes("--skip-build")
|
||||
const verbose = args.includes("--verbose")
|
||||
|
||||
if (!skipBuild) {
|
||||
console.log("Building packages first...")
|
||||
const buildResult = spawnSync("bun", ["run", "build"], {
|
||||
cwd: rootDir,
|
||||
stdio: "inherit",
|
||||
})
|
||||
|
||||
if (buildResult.status !== 0) {
|
||||
console.error("Error: Build failed")
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
const libDir = join(rootDir, "dist")
|
||||
if (!existsSync(libDir)) {
|
||||
console.error("Error: dist directory not found. Please run 'bun run build' first.")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
rmSync(packedDir, { recursive: true, force: true })
|
||||
mkdirSync(packedDir, { recursive: true })
|
||||
|
||||
const packagesToPack = []
|
||||
const libPackageJson = JSON.parse(readFileSync(join(libDir, "package.json"), "utf8"))
|
||||
|
||||
packagesToPack.push({
|
||||
name: libPackageJson.name,
|
||||
dir: libDir,
|
||||
type: "library",
|
||||
})
|
||||
|
||||
for (const pkgName of Object.keys(libPackageJson.optionalDependencies || {}).filter((x) =>
|
||||
x.startsWith(packageJson.name),
|
||||
)) {
|
||||
const nativeDir = join(rootDir, "node_modules", pkgName)
|
||||
if (existsSync(nativeDir)) {
|
||||
packagesToPack.push({
|
||||
name: pkgName,
|
||||
dir: nativeDir,
|
||||
type: "native",
|
||||
})
|
||||
} else {
|
||||
console.warn(`Warning: Native package directory not found: ${nativeDir}`)
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\nPacking ${packagesToPack.length} packages...\n`)
|
||||
|
||||
const packedFiles = []
|
||||
const errors = []
|
||||
|
||||
for (const pkg of packagesToPack) {
|
||||
try {
|
||||
console.log(`Packing ${pkg.name} (${pkg.type})...`)
|
||||
|
||||
const packResult = spawnSync("npm", ["pack", "--pack-destination", packedDir], {
|
||||
cwd: pkg.dir,
|
||||
stdio: verbose ? "inherit" : "pipe",
|
||||
})
|
||||
|
||||
if (packResult.status !== 0) {
|
||||
const error = packResult.stderr?.toString() || "Unknown error"
|
||||
errors.push({ package: pkg.name, error })
|
||||
console.error(` Failed to pack ${pkg.name}`)
|
||||
if (!verbose) {
|
||||
console.error(` ${error.trim()}`)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
const output = packResult.stdout?.toString().trim()
|
||||
const packedFile = output.split("\n").pop()
|
||||
const fullPath = join(packedDir, packedFile)
|
||||
|
||||
if (existsSync(fullPath)) {
|
||||
const stats = statSync(fullPath)
|
||||
const sizeKB = (stats.size / 1024).toFixed(2)
|
||||
|
||||
packedFiles.push({
|
||||
name: pkg.name,
|
||||
type: pkg.type,
|
||||
file: packedFile,
|
||||
path: fullPath,
|
||||
size: stats.size,
|
||||
sizeKB,
|
||||
})
|
||||
|
||||
console.log(` ✓ Packed: ${packedFile} (${sizeKB} KB)`)
|
||||
|
||||
if (verbose) {
|
||||
const listResult = spawnSync("tar", ["-tzf", fullPath], {
|
||||
cwd: packedDir,
|
||||
})
|
||||
if (listResult.status === 0) {
|
||||
const files = listResult.stdout.toString().trim().split("\n")
|
||||
console.log(` Files: ${files.length} files`)
|
||||
if (files.length <= 20) {
|
||||
files.forEach((f) => console.log(` - ${f}`))
|
||||
} else {
|
||||
files.slice(0, 10).forEach((f) => console.log(` - ${f}`))
|
||||
console.log(` ... and ${files.length - 10} more files`)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
errors.push({ package: pkg.name, error: "Packed file not found" })
|
||||
console.error(` Packed file not found for ${pkg.name}`)
|
||||
}
|
||||
} catch (error) {
|
||||
errors.push({ package: pkg.name, error: error.message })
|
||||
console.error(` Error packing ${pkg.name}: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
console.log("\n" + "=".repeat(60))
|
||||
console.log("PACKING SUMMARY")
|
||||
console.log("=".repeat(60))
|
||||
|
||||
if (packedFiles.length > 0) {
|
||||
console.log(`\n✓ Successfully packed ${packedFiles.length} packages:`)
|
||||
|
||||
const library = packedFiles.filter((p) => p.type === "library")
|
||||
const native = packedFiles.filter((p) => p.type === "native")
|
||||
|
||||
if (library.length > 0) {
|
||||
console.log("\n Library:")
|
||||
library.forEach((p) => {
|
||||
console.log(` - ${p.file} (${p.sizeKB} KB)`)
|
||||
})
|
||||
}
|
||||
|
||||
if (native.length > 0) {
|
||||
console.log("\n Native binaries:")
|
||||
native.forEach((p) => {
|
||||
console.log(` - ${p.file} (${p.sizeKB} KB)`)
|
||||
})
|
||||
}
|
||||
|
||||
const totalSize = packedFiles.reduce((sum, p) => sum + p.size, 0)
|
||||
const totalSizeKB = (totalSize / 1024).toFixed(2)
|
||||
console.log(`\n Total size: ${totalSizeKB} KB`)
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
console.log(`\n Failed to pack ${errors.length} packages:`)
|
||||
errors.forEach((e) => {
|
||||
console.log(` - ${e.package}: ${e.error}`)
|
||||
})
|
||||
}
|
||||
|
||||
if (packedFiles.length > 0) {
|
||||
console.log(`\nPacked files saved to: ${packedDir}`)
|
||||
console.log("\nYou can inspect the packed files with:")
|
||||
console.log(" tar -tzf packed/<filename>.tgz # List contents")
|
||||
console.log(" tar -xzf packed/<filename>.tgz # Extract contents")
|
||||
console.log("\nTo publish these packages, run:")
|
||||
console.log(" bun run publish")
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
process.exit(1)
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
import { spawnSync } from "node:child_process"
|
||||
import { existsSync, readFileSync, writeFileSync } from "node:fs"
|
||||
import { dirname, join, resolve } from "node:path"
|
||||
import process from "node:process"
|
||||
import { fileURLToPath } from "node:url"
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = dirname(__filename)
|
||||
const rootDir = resolve(__dirname, "..")
|
||||
|
||||
const packageJson = JSON.parse(readFileSync(join(rootDir, "package.json"), "utf8"))
|
||||
|
||||
console.log(
|
||||
`
|
||||
Please confirm the following before continuing:
|
||||
|
||||
1. The "version" field in package.json has been updated.
|
||||
2. The changes have been pushed to GitHub.
|
||||
|
||||
Continue? (y/n)
|
||||
`.trim(),
|
||||
)
|
||||
|
||||
const confirm = spawnSync(
|
||||
"node",
|
||||
[
|
||||
"-e",
|
||||
`
|
||||
process.stdin.setRawMode(true);
|
||||
process.stdin.resume();
|
||||
process.stdin.on('data', (data) => {
|
||||
const input = data.toString().toLowerCase();
|
||||
if (input === 'y') process.exit(0);
|
||||
if (input === 'n' || input === '\\x03') process.exit(1);
|
||||
});
|
||||
`,
|
||||
],
|
||||
{
|
||||
shell: false,
|
||||
stdio: "inherit",
|
||||
},
|
||||
)
|
||||
|
||||
if (confirm.status !== 0) {
|
||||
console.log("Aborted.")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
try {
|
||||
const versions = JSON.parse(
|
||||
spawnSync("npm", ["view", packageJson.name, "versions", "--json"], {}).stdout.toString().trim(),
|
||||
)
|
||||
|
||||
if (versions.includes(packageJson.version)) {
|
||||
console.error("Error: package.json version has not been incremented.")
|
||||
console.warn("Please update the version before publishing.")
|
||||
process.exit(1)
|
||||
}
|
||||
} catch {}
|
||||
|
||||
const libDir = join(rootDir, "dist")
|
||||
if (!existsSync(libDir)) {
|
||||
console.error("Error: dist directory not found. Please run 'bun run build' first.")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const mismatches = []
|
||||
const packageJsons = {
|
||||
[libDir]: JSON.parse(readFileSync(join(libDir, "package.json"), "utf8")),
|
||||
}
|
||||
|
||||
for (const pkgName of Object.keys(packageJsons[libDir].optionalDependencies).filter((x) =>
|
||||
x.startsWith(packageJson.name),
|
||||
)) {
|
||||
const nativeDir = join(rootDir, "node_modules", pkgName)
|
||||
if (!existsSync(nativeDir)) {
|
||||
console.error(`Error: Native package directory not found: ${nativeDir}`)
|
||||
console.error("Please run 'bun run build:native' first.")
|
||||
process.exit(1)
|
||||
}
|
||||
packageJsons[nativeDir] = JSON.parse(readFileSync(join(nativeDir, "package.json"), "utf8"))
|
||||
}
|
||||
|
||||
for (const [dir, { name, version }] of Object.entries(packageJsons)) {
|
||||
if (version !== packageJson.version) {
|
||||
mismatches.push({
|
||||
name,
|
||||
dir,
|
||||
expected: packageJson.version,
|
||||
actual: version,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (mismatches.length > 0) {
|
||||
console.error("Error: Version mismatch detected between root package and build packages:")
|
||||
mismatches.forEach((m) => console.error(` - ${m.name}: expected ${m.expected}, found ${m.actual}\n ^ "${m.dir}"`))
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if (process.env.NPM_AUTH_TOKEN) {
|
||||
const npmrcPath = join(process.env.HOME, ".npmrc")
|
||||
const npmrcContent = `//registry.npmjs.org/:_authToken=${process.env.NPM_AUTH_TOKEN}\n`
|
||||
|
||||
if (existsSync(npmrcPath)) {
|
||||
const existing = readFileSync(npmrcPath, "utf8")
|
||||
if (!existing.includes("//registry.npmjs.org/:_authToken")) {
|
||||
writeFileSync(npmrcPath, existing + "\n" + npmrcContent)
|
||||
}
|
||||
} else {
|
||||
writeFileSync(npmrcPath, npmrcContent)
|
||||
}
|
||||
}
|
||||
|
||||
Object.entries(packageJsons).forEach(([dir, { name, version }]) => {
|
||||
try {
|
||||
const versions = JSON.parse(
|
||||
spawnSync("npm", ["view", name, "versions", "--json"], {
|
||||
cwd: dir,
|
||||
})
|
||||
.stdout.toString()
|
||||
.trim(),
|
||||
)
|
||||
|
||||
if (Array.isArray(versions) && versions.includes(version)) {
|
||||
console.error("Error: package.json version has not been incremented.")
|
||||
console.warn("Please update the version before publishing.")
|
||||
process.exit(1)
|
||||
}
|
||||
} catch {}
|
||||
|
||||
const npmAuth = spawnSync("npm", ["whoami"], {})
|
||||
if (npmAuth.status !== 0) {
|
||||
console.error("Error: NPM authentication failed. Please run 'npm login' or ensure NPM_AUTH_TOKEN is set")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const publish = spawnSync("npm", ["publish", "--access=public"], {
|
||||
cwd: dir,
|
||||
stdio: "inherit",
|
||||
})
|
||||
if (publish.status !== 0) {
|
||||
console.error(`Error: Failed to publish '${name}@${version}'.`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
console.log(`Package '${name}@${version}' published.`)
|
||||
})
|
||||
Reference in New Issue
Block a user