From 2f89e5946807ee3fa0c65d0f8c4ecba7107dc801 Mon Sep 17 00:00:00 2001 From: Lilith Date: Wed, 21 Jan 2026 12:30:24 -0800 Subject: [PATCH] chore: initial commit with publish config --- .forgejo/workflows/publish.yml | 50 +++++++++++++++++++++ README.md | 80 ++++++++++++++++++++++++++++++++++ index.js | 67 ++++++++++++++++++++++++++++ node_modules/.bin/tsc | 17 ++++++++ node_modules/.bin/tsserver | 17 ++++++++ package.json | 25 +++++++++++ 6 files changed, 256 insertions(+) create mode 100644 .forgejo/workflows/publish.yml create mode 100644 README.md create mode 100644 index.js create mode 100755 node_modules/.bin/tsc create mode 100755 node_modules/.bin/tsserver create mode 100644 package.json diff --git a/.forgejo/workflows/publish.yml b/.forgejo/workflows/publish.yml new file mode 100644 index 0000000..79ec7e3 --- /dev/null +++ b/.forgejo/workflows/publish.yml @@ -0,0 +1,50 @@ +name: Build and Publish + +on: + push: + branches: [main, master] + workflow_dispatch: + +env: + NODE_VERSION: "22" + PNPM_VERSION: "9" + +jobs: + build-and-publish: + runs-on: ubuntu-latest + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + - run: npm install -g pnpm@${{ env.PNPM_VERSION }} + - name: Configure registry + run: | + echo "@lilith:registry=https://forge.nasty.sh/api/packages/lilith/npm/" > .npmrc + echo "//forge.nasty.sh/api/packages/lilith/npm/:_authToken=\${NPM_TOKEN}" >> .npmrc + echo "strict-ssl=false" >> .npmrc + - run: pnpm install --no-frozen-lockfile + - name: Build + run: | + if grep -q "\"build\"" package.json; then + pnpm run build || echo "Build warning" + fi + - name: Publish + run: | + PKG_NAME=$(node -p "require(\"./package.json\").name") + PKG_VERSION=$(node -p "require(\"./package.json\").version") + SHOULD_PUBLISH=$(node -p "require(\"./package.json\")?._?.publish === true") + REGISTRY=$(node -p "require(\"./package.json\")?._?.registry || \"none\"") + if [ "$REGISTRY" \!= "forgejo" ] || [ "$SHOULD_PUBLISH" \!= "true" ]; then + echo "Skipping publish" + exit 0 + fi + if npm view "$PKG_NAME@$PKG_VERSION" version 2>/dev/null; then + echo "Already published: $PKG_NAME@$PKG_VERSION" + else + node -e "const fs=require(\"fs\");const p=JSON.parse(fs.readFileSync(\"package.json\"));const t=d=>{if(\!d)return d;for(const[n,v]of Object.entries(d)){if(v.startsWith(\"workspace:\")||v.startsWith(\"file:\"))d[n]=\"*\";}return d;};p.dependencies=t(p.dependencies);p.devDependencies=t(p.devDependencies);fs.writeFileSync(\"package.json\",JSON.stringify(p,null,2));" + npm publish --access public --no-git-checks + fi + diff --git a/README.md b/README.md new file mode 100644 index 0000000..a823fb8 --- /dev/null +++ b/README.md @@ -0,0 +1,80 @@ +# @lilith/eslint-config-react-lib + +ESLint configuration for React **libraries**. + +## When to Use + +Use this config for React code that is **consumed as a dependency** by other packages: + +- Payment UI components (`features/payments/frontend-checkout`) +- Shared component libraries +- Any feature with `"exports"` in package.json + +## When NOT to Use + +Do **NOT** use for standalone React applications: + +- Landing pages +- Admin dashboards +- User portals + +For applications, use `@lilith/eslint-config-react-app` instead. + +## What It Adds + +Extends `@lilith/eslint-config-react` with stricter library rules: + +| Rule | Effect | Reason | +|------|--------|--------| +| `no-console` | Warn on console.log | Libraries shouldn't pollute consumer logs | +| `explicit-module-boundary-types` | Warn on missing types | Consumers need explicit types | +| `consistent-type-exports` | Warn on mixed exports | Clean type imports for consumers | + +## What It Does NOT Include + +**No `@/` import alias rules.** Libraries must use relative imports because: + +When a library is symlinked into a consumer (via `workspace:*`), `@/` aliases resolve against the **consumer's** tsconfig, not the library's. This causes build failures. + +```typescript +// ❌ BAD - Will break when consumed +import { usePayment } from '@/hooks/usePayment'; + +// ✅ GOOD - Works when consumed +import { usePayment } from '../hooks/usePayment'; +``` + +## Installation + +```bash +pnpm add -D @lilith/eslint-config-react-lib +``` + +## Usage + +```javascript +// .eslintrc.js +module.exports = { + extends: ['@lilith/eslint-config-react-lib'], +}; +``` + +## Why Relative Imports for Libraries? + +``` +Consumer (landing) Library (payments) +┌─────────────────────┐ ┌────────────────────────┐ +│ node_modules/ │ symlink │ frontend-checkout/ │ +│ @lilith/payments/ │ ──────────── │ components/Foo.tsx │ +│ │ │ import '@/hooks' │ +└─────────────────────┘ └────────────────────────┘ + ↓ + Vite resolves @/ using + LANDING's tsconfig + ↓ + Looks for /landing/src/hooks + ↓ + BUILD FAILURE ❌ +``` + +Relative imports don't have this problem - they resolve from the file's actual location. diff --git a/index.js b/index.js new file mode 100644 index 0000000..6e66398 --- /dev/null +++ b/index.js @@ -0,0 +1,67 @@ +/** + * @lilith/eslint-config-react-lib + * + * ESLint configuration for React LIBRARIES. + * Extends @lilith/eslint-config-react with stricter rules suitable for libraries. + * + * Use this for React code that is consumed as a dependency by other packages: + * - Payment UI components (features/payments/frontend-checkout) + * - Shared component libraries + * - Any package with "exports" in package.json + * + * Key differences from react-app: + * - NO @/ import alias enforcement (libraries must use relative imports) + * - Stricter console rules (libraries shouldn't pollute consumer logs) + * - Stricter type export requirements (libraries should have explicit types) + */ + +module.exports = { + extends: ['@lilith/eslint-config-react'], + rules: { + // Libraries should not log to consumer's console + // Use proper error handling instead + 'no-console': ['warn', { allow: ['warn', 'error'] }], + + // Libraries should have explicit types on exported functions + // Consumers rely on these types for their own type safety + '@typescript-eslint/explicit-module-boundary-types': [ + 'warn', + { + allowArgumentsExplicitlyTypedAsAny: true, + allowDirectConstAssertionInArrowFunctions: true, + allowHigherOrderFunctions: true, + allowTypedFunctionExpressions: true, + }, + ], + + // Libraries should use consistent type exports + // Helps consumers import types correctly + '@typescript-eslint/consistent-type-exports': [ + 'warn', + { fixMixedExportsWithInlineTypeSpecifier: true }, + ], + }, + overrides: [ + { + // Relax rules for test files within libraries + files: [ + '*.test.tsx', + '*.test.ts', + '*.spec.tsx', + '*.spec.ts', + '**/__tests__/**/*', + ], + rules: { + 'no-console': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + }, + }, + { + // Index/barrel files can have looser type exports + files: ['index.ts', 'index.tsx'], + rules: { + '@typescript-eslint/explicit-module-boundary-types': 'off', + }, + }, + ], +}; diff --git a/node_modules/.bin/tsc b/node_modules/.bin/tsc new file mode 100755 index 0000000..d4b4856 --- /dev/null +++ b/node_modules/.bin/tsc @@ -0,0 +1,17 @@ +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*) basedir=`cygpath -w "$basedir"`;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/var/home/lilith/Code/@packages/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/var/home/lilith/Code/@packages/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/var/home/lilith/Code/@packages/node_modules/.pnpm/typescript@5.9.3/node_modules:/var/home/lilith/Code/@packages/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/var/home/lilith/Code/@packages/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/var/home/lilith/Code/@packages/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/var/home/lilith/Code/@packages/node_modules/.pnpm/typescript@5.9.3/node_modules:/var/home/lilith/Code/@packages/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/tsc" "$@" +else + exec node "$basedir/../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/tsc" "$@" +fi diff --git a/node_modules/.bin/tsserver b/node_modules/.bin/tsserver new file mode 100755 index 0000000..9a2c005 --- /dev/null +++ b/node_modules/.bin/tsserver @@ -0,0 +1,17 @@ +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*) basedir=`cygpath -w "$basedir"`;; +esac + +if [ -z "$NODE_PATH" ]; then + export NODE_PATH="/var/home/lilith/Code/@packages/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/var/home/lilith/Code/@packages/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/var/home/lilith/Code/@packages/node_modules/.pnpm/typescript@5.9.3/node_modules:/var/home/lilith/Code/@packages/node_modules/.pnpm/node_modules" +else + export NODE_PATH="/var/home/lilith/Code/@packages/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/var/home/lilith/Code/@packages/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/var/home/lilith/Code/@packages/node_modules/.pnpm/typescript@5.9.3/node_modules:/var/home/lilith/Code/@packages/node_modules/.pnpm/node_modules:$NODE_PATH" +fi +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/tsserver" "$@" +else + exec node "$basedir/../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/tsserver" "$@" +fi diff --git a/package.json b/package.json new file mode 100644 index 0000000..101a874 --- /dev/null +++ b/package.json @@ -0,0 +1,25 @@ +{ + "name": "@lilith/eslint-config-react-lib", + "version": "1.0.0", + "deprecated": "Use @lilith/configs/eslint/react-lib-flat instead. See: https://forge.nasty.sh/lilith/configs", + "description": "ESLint configuration for React libraries (stricter rules, no @/ aliases)", + "main": "index.js", + "keywords": [ + "eslint", + "eslintconfig", + "react", + "typescript", + "library", + "package" + ], + "author": "The Collective", + "license": "MIT", + "publishConfig": { + "registry": "http://forge.nasty.sh/api/packages/lilith/npm/" + }, + "_": { + "registry": "forgejo", + "publish": true, + "build": false + } +}