diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..ed19d9c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,10 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +quote_type = single diff --git a/.github/workflows/commit.yaml b/.github/workflows/commit.yaml new file mode 100644 index 0000000..909880d --- /dev/null +++ b/.github/workflows/commit.yaml @@ -0,0 +1,30 @@ +name: Commit check + +on: + push: + branches: + - master + +env: + COMMIT_OWNER: ${{ github.event.pusher.name }} + COMMIT_SHA: ${{ github.sha }} + PIPELINE_ID: ${{ github.run_number }} + APP_BRANCH_NAME: ${{ github.ref_name }} + DOCKER_REGISTRY: registry.cn-hangzhou.aliyuncs.com + FORCE_COLOR: 1 + +jobs: + commit: + name: commit + runs-on: [linux-64] + steps: + - uses: actions/checkout@v4 + - name: Check + run: | + earthly --ci --allow-privileged +ci-check \ + --PIPELINE_ID=${{ env.PIPELINE_ID }} + - name: Release + run: | + earthly --ci --allow-privileged --push +ci-release \ + --PIPELINE_ID=${{ env.PIPELINE_ID }} \ + --NPM_ACCESS_TOKEN=${{ secrets.NPM_ACCESS_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9b1ee42 --- /dev/null +++ b/.gitignore @@ -0,0 +1,175 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Caches + +.cache + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..696750c --- /dev/null +++ b/.npmrc @@ -0,0 +1,3 @@ +shamefully-hoist=true +registry=https://registry.npmmirror.com +auto-install-peers=true diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..3516580 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +20.17.0 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..4fb1c89 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,13 @@ +# Ignore artifacts: +build +coverage +dist +public +styles +node_modules +.vscode +dist +.nuxt +.output +.yaml +.github/* diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..7306833 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,12 @@ +{ + "printWidth": 250, + "tabWidth": 2, + "useTabs": false, + "semi": true, + "singleQuote": true, + "trailingComma": "es5", + "bracketSpacing": true, + "bracketSameLine": false, + "arrowParens": "always", + "vueIndentScriptAndStyle": false +} diff --git a/Earthfile b/Earthfile new file mode 100644 index 0000000..c72deac --- /dev/null +++ b/Earthfile @@ -0,0 +1,42 @@ +VERSION 0.8 +ARG --global BASE_IMAGE=earthly/dind:alpine +ARG --global NODE_IMAGE=node:20.17.0 + +FROM ${BASE_IMAGE} +WORKDIR /app +COPY .version . +ARG --global PIPELINE_ID +ARG --global APP_BASE_VERSION=$(cat .version | head -1) +ARG --global APP_VERSION=${APP_BASE_VERSION}.${PIPELINE_ID} +ARG --global NPM_ACCESS_TOKEN + +build-base: + FROM ${NODE_IMAGE} + WORKDIR /app + COPY bun.lockb \ + package.json \ + .npmrc \ + . + RUN npm install -g bun --registry=https://registry.npmmirror.com + RUN bun install --frozen-lockfile + SAVE ARTIFACT node_modules AS LOCAL node_modules + +check: + FROM +build-base + COPY . . + RUN bun run build:check + +release: + FROM +build-base + COPY . . + RUN npm config set //registry.npmjs.org/:_authToken=${NPM_ACCESS_TOKEN} + RUN npm version ${APP_VERSION} --no-commit-hooks --no-git-tag-version --allow-same-version + RUN bun run build + RUN bun run release + +ci-check: + BUILD +check + +ci-release: + BUILD +release + diff --git a/LICENSE b/LICENSE.md similarity index 100% rename from LICENSE rename to LICENSE.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..cc611ae --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# mesh + +To install dependencies: + +```bash +bun install +``` + +To run: + +```bash +bun run index.ts +``` + +This project was created using `bun init` in bun v1.1.27. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000..5a17207 Binary files /dev/null and b/bun.lockb differ diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..ea25dc8 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,68 @@ +import antfu from '@antfu/eslint-config'; + +export default antfu( + { + stylistic: { + indent: 2, // 4, or 'tab' + quotes: 'single', // or 'double' + }, + lessOpinionated: true, + typescript: true, + javascript: false, + vue: { + overrides: { + 'vue/component-tags-order': ['error', { order: ['template', 'script', 'style'] }], + 'vue/block-order': ['error', { order: ['template', 'script', 'style'] }], + 'vue/component-name-in-template-casing': [ + 'error', + 'kebab-case', + { + registeredComponentsOnly: true, + ignores: [], + }, + ], + 'vue/no-unused-refs': 'off', + 'vue/no-template-shadow': 'off', + 'vue/valid-define-emits': 'off', + 'vue/attribute-hyphenation': 'error', + 'vue/html-closing-bracket-spacing': 'off', + 'vue/require-explicit-emits': ['error', { allowProps: true }], + 'vue/define-emits-declaration': ['error', 'type-based'], + 'vue/custom-event-name-casing': ['error', 'camelCase'], + 'vue/prop-name-casing': ['error', 'camelCase'], + 'vue/singleline-html-element-content-newline': 'off', + }, + }, + // unocss: true, + jsonc: false, + yaml: false, + jsx: false, + }, + { + rules: { + 'no-console': 'off', + 'import/no-absolute-path': ['error'], + 'import/no-relative-packages': ['error'], + 'import/no-self-import': ['error'], + 'style/brace-style': ['error', '1tbs'], + 'style/comma-dangle': ['error', 'only-multiline'], + 'style/semi': ['error', 'always'], + 'style/quote-props': ['error', 'as-needed'], + 'style/arrow-parens': ['error', 'always'], + 'style/nonblock-statement-body-position': ['error', 'below'], + 'style/member-delimiter-style': [ + 'error', + { + multiline: { delimiter: 'semi', requireLast: true }, + singleline: { delimiter: 'semi', requireLast: false }, + }, + ], + 'ts/ban-ts-comment': 'off', + 'ts/ban-ts-ignore': 'off', + 'ts/prefer-ts-expect-error': 'off', + 'ts/ban-types': 'off', + 'unused-imports/no-unused-vars': 'off', + 'ts/no-use-before-define': 'off', + }, + } +); diff --git a/package.json b/package.json new file mode 100644 index 0000000..9d76bfa --- /dev/null +++ b/package.json @@ -0,0 +1,53 @@ +{ + "name": "@mesh/monorepo", + "module": "index.ts", + "type": "module", + "version": "0.0.0", + "private": true, + "workspaces": [ + "packages/*", + "apps/*" + ], + "scripts": { + "setup": "rm -rf **/node_modules **/dist && bun install", + "link": "bun --filter './packages/*' dev:link", + "release": "bun run build && bunx @morlay/bunpublish", + "build": "NODE_ENV=production && pnpm run build:packages", + "build:check": "pnpm run format:check && pnpm run security:check", + "build:packages": "bun run build:lang", + "build:lang": "bun --filter './packages/lang' build", + "dev": "pnpm --filter showcase dev", + "module:dev": "pnpm --filter @primevue/nuxt-module dev", + "security:check": "pnpm audit --prod --audit-level high", + "format": "prettier --write \"**/*.{vue,js,mjs,ts,d.ts}\" --cache", + "format:check": "prettier --check \"**/*.{vue,js,mjs,ts,d.ts}\"", + "lint": "eslint . --cache", + "lint:fix": "eslint --fix .", + "test:unit": "pnpm --filter primevue test:unit" + }, + "devDependencies": { + "@antfu/eslint-config": "^3.6.2", + "@types/bun": "latest", + "@types/fs-extra": "^11.0.4", + "@typescript-eslint/eslint-plugin": "^8.6.0", + "@typescript-eslint/parser": "^8.6.0", + "@typescript-eslint/type-utils": "^8.6.0", + "@typescript-eslint/types": "^8.6.0", + "@typescript-eslint/typescript-estree": "^8.6.0", + "@typescript-eslint/utils": "^8.6.0", + "eslint": "^9.10.0", + "eslint-plugin-unused-imports": "^4.1.4", + "eslint-plugin-vue": "^9.28.0", + "pnpm": "^9.10.0", + "prettier": "^3.3.3", + "taze": "^0.16.7", + "typescript": "^5.0.0" + }, + "publishConfig": { + "access": "public" + }, + "engines": { + "node": ">=20.17.0", + "bun": ">=1" + } +} diff --git a/packages/lang/README.md b/packages/lang/README.md new file mode 100644 index 0000000..e69de29 diff --git a/packages/lang/package.json b/packages/lang/package.json new file mode 100644 index 0000000..75e6758 --- /dev/null +++ b/packages/lang/package.json @@ -0,0 +1,37 @@ +{ + "name": "@mesh/lang", + "version": "0.0.0", + "main": "./src/index.ts", + "module": "./src/index.ts", + "publishConfig": { + "main": "./index.mjs", + "module": "./index.mjs", + "types": "./index.d.mts", + "exports": { + ".": { + "types": "./index.d.mts", + "import": "./index.mjs" + } + }, + "directory": "dist", + "linkDirectory": false, + "access": "public", + "registry": "https://registry.npmjs.org/" + }, + "scripts": { + "build": "NODE_ENV=production INPUT_DIR=./ OUTPUT_DIR=dist/ bun run build:package", + "build:package": "bun run build:prebuild && tsup && bun run build:postbuild", + "build:prebuild": "bun ./scripts/prebuild.ts", + "build:postbuild": "bun ./scripts/postbuild.ts", + "dev:link": "bun link --global && bun link" + }, + "devDependencies": { + "tsup": "^8.2.4" + }, + "repository": {}, + "bugs": {}, + "engines": { + "node": ">=20.17.0", + "bun": ">=1" + } +} \ No newline at end of file diff --git a/packages/lang/scripts/postbuild.ts b/packages/lang/scripts/postbuild.ts new file mode 100644 index 0000000..b935b82 --- /dev/null +++ b/packages/lang/scripts/postbuild.ts @@ -0,0 +1,11 @@ +import path from 'node:path'; +import fs from 'fs-extra'; +import { clearPackageJson, resolvePath } from '../../../scripts/build-helper'; + +const { __dirname, __workspace, OUTPUT_DIR } = resolvePath(import.meta.url); + +fs.copySync(path.resolve(__dirname, '../package.json'), `${OUTPUT_DIR}/package.json`); +fs.copySync(path.resolve(__dirname, '../README.md'), `${OUTPUT_DIR}/README.md`); +fs.copySync(path.resolve(__workspace, './LICENSE.md'), `${OUTPUT_DIR}/LICENSE.md`); + +clearPackageJson(path.resolve(__dirname, `../${OUTPUT_DIR}/package.json`)); diff --git a/packages/lang/scripts/prebuild.ts b/packages/lang/scripts/prebuild.ts new file mode 100644 index 0000000..06c3d2e --- /dev/null +++ b/packages/lang/scripts/prebuild.ts @@ -0,0 +1,5 @@ +import path from 'node:path'; +import { removeBuild, resolvePath, updatePackageJson } from '../../../scripts/build-helper'; + +removeBuild(import.meta.url); +updatePackageJson(path.resolve(resolvePath(import.meta.url).__dirname, '../package.json')); diff --git a/packages/lang/src/expressions.ts b/packages/lang/src/expressions.ts new file mode 100644 index 0000000..beb6f82 --- /dev/null +++ b/packages/lang/src/expressions.ts @@ -0,0 +1,2 @@ +export type HasAll = (...value: T[]) => boolean; +export type HasAny = (...value: T[]) => boolean; diff --git a/packages/lang/src/functions.ts b/packages/lang/src/functions.ts new file mode 100644 index 0000000..588ef32 --- /dev/null +++ b/packages/lang/src/functions.ts @@ -0,0 +1,4 @@ +export type Consumer = (value: T) => void; +export type Supplier = () => T; +export type Predicate = (value: T) => boolean; +export type Function = (value: T) => R; diff --git a/packages/lang/src/index.ts b/packages/lang/src/index.ts new file mode 100644 index 0000000..002955a --- /dev/null +++ b/packages/lang/src/index.ts @@ -0,0 +1,2 @@ +export * from './expressions'; +export * from './functions'; diff --git a/packages/lang/tsconfig.json b/packages/lang/tsconfig.json new file mode 100644 index 0000000..36d34ac --- /dev/null +++ b/packages/lang/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "module": "ESNext", + "moduleResolution": "Node", + "baseUrl": ".", + }, + "exclude": ["node_modules", "dist"] +} diff --git a/packages/lang/tsup.config.ts b/packages/lang/tsup.config.ts new file mode 100644 index 0000000..6302f95 --- /dev/null +++ b/packages/lang/tsup.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'tsup'; + +export default defineConfig({ + entry: ['src/index.ts'], + format: ['esm'], + dts: true, + splitting: false, +}); diff --git a/scripts/build-helper.ts b/scripts/build-helper.ts new file mode 100644 index 0000000..97529e4 --- /dev/null +++ b/scripts/build-helper.ts @@ -0,0 +1,96 @@ +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import fs from 'fs-extra'; + +export const resolvePath = (metaUrl?: string) => { + const __dirname = path.dirname(fileURLToPath(metaUrl || import.meta.url)); + const __workspace = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../'); + const { INPUT_DIR, OUTPUT_DIR } = process.env; + const INPUT_PATH = path.resolve(__dirname, process.env.INPUT_DIR); + const OUTPUT_PATH = path.resolve(__dirname, process.env.OUTPUT_DIR); + + return { + __dirname, + __workspace, + INPUT_DIR, + OUTPUT_DIR, + INPUT_PATH, + OUTPUT_PATH, + }; +}; + +export const removeBuild = (metaUrl?: string) => { + const { OUTPUT_DIR } = resolvePath(metaUrl); + + fs.remove(OUTPUT_DIR); +}; + +export const updatePackageJson = (localPackageJson: string) => { + const { __workspace } = resolvePath(); + const packageJson = JSON.parse( + fs.readFileSync(path.resolve(__workspace, './package.json'), { + encoding: 'utf8', + flag: 'r', + }) + ); + const pkg = JSON.parse(fs.readFileSync(localPackageJson, { encoding: 'utf8', flag: 'r' })); + + pkg.version = packageJson.version; + pkg.author = packageJson.author; + pkg.homepage = packageJson.homepage; + pkg.license = packageJson.license; + pkg.repository = { ...pkg.repository, ...packageJson.repository }; + pkg.bugs = { ...pkg.bugs, ...packageJson.bugs }; + pkg.engines = { ...pkg.engines, ...packageJson.engines }; + + fs.writeFileSync(localPackageJson, JSON.stringify(pkg, null, 4)); +}; + +export const clearPackageJson = (localPackageJson: string) => { + const pkg = JSON.parse(fs.readFileSync(localPackageJson, { encoding: 'utf8', flag: 'r' })); + + delete pkg?.scripts; + delete pkg?.devDependencies; + delete pkg?.publishConfig?.directory; + delete pkg?.publishConfig?.linkDirectory; + fs.writeFileSync(localPackageJson, JSON.stringify(pkg, null, 4)); +}; + +export const copyDependencies = (inFolder: string, outFolder: string, subFolder: string) => { + fs.readdirSync(inFolder, { withFileTypes: true }).forEach((entry) => { + const fileName = entry.name; + const sourcePath = path.join(inFolder, fileName); + const destPath = path.join(outFolder, fileName); + + if (entry.isDirectory()) { + copyDependencies(sourcePath, destPath, subFolder); + } else { + if (fileName.endsWith('d.ts') || fileName.endsWith('.vue')) { + if (subFolder && sourcePath.includes(subFolder)) { + const subDestPath = path.join(outFolder, fileName.replace(subFolder, '')); + + fs.ensureDirSync(path.dirname(subDestPath)); + fs.copyFileSync(sourcePath, subDestPath); + } else { + fs.ensureDirSync(path.dirname(destPath)); + fs.copyFileSync(sourcePath, destPath); + } + } + } + }); +}; + +export const renameDTSFile = async (dir: string, newName: string) => { + const entries = await fs.readdir(dir, { withFileTypes: true }); + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + + if (entry.isDirectory()) { + await renameDTSFile(fullPath, newName); + } else if (entry.name.endsWith('.d.ts')) { + const newFullPath = path.join(dir, `${newName}.d.ts`); + + await fs.rename(fullPath, newFullPath); + } + } +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..238655f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + // Enable latest features + "lib": ["ESNext", "DOM"], + "target": "ESNext", + "module": "ESNext", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } +}