commit b4bb3e3eedd272ad2b3ed771f62330a140acafbd Author: Pascal Perrenoud Date: Thu Sep 11 13:41:58 2025 +0200 init repo diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7f82a6f --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +package-lock.json +._* +.idea/ +.DS_Store +node_modules/ +dist/ diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..aa0e10b --- /dev/null +++ b/.npmignore @@ -0,0 +1,7 @@ +.woodpecker/ +test/ +.gitignore +README.md +.prettierignore +.prettierrc +eslint.config.ts diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..2922a2b --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +.woodpecker +node_modules +test +dist diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..9e19544 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,11 @@ +{ + "arrowParens": "avoid", + "tabWidth": 2, + "useTabs": false, + "bracketSpacing": false, + "printWidth": 120, + "semi": false, + "singleQuote": true, + "jsxSingleQuote": true, + "trailingComma": "none" +} diff --git a/.woodpecker/test.yml b/.woodpecker/test.yml new file mode 100644 index 0000000..e8d85bd --- /dev/null +++ b/.woodpecker/test.yml @@ -0,0 +1,19 @@ +when: + - path: + include: ['src/**/*.ts'] + +steps: + install: + image: node + when: + - event: [pull_request, push, manual] + commands: + - npm install + + test: + image: oven/bun:alpine + when: + - event: [pull_request, push, manual] + depends_on: install + commands: + - bun test diff --git a/README.md b/README.md new file mode 100644 index 0000000..9922c93 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# Library template +Basic template to create a TypeScript library that works properly when included + +## How to split in multiple file +Technically, there is nothing to do, but if you want to allow sub-imports, you have to : + +1. In `package.json`, under `exports`, add `"./submodule": "./src/submodule.ts"` +2. In `tsconfig.json`, under `paths`, add `"lib-name/*": ["./src/*"]` diff --git a/eslint.config.ts b/eslint.config.ts new file mode 100644 index 0000000..754d790 --- /dev/null +++ b/eslint.config.ts @@ -0,0 +1,15 @@ +import js from '@eslint/js' +import globals from 'globals' +import tseslint from 'typescript-eslint' +import {defineConfig, globalIgnores} from 'eslint/config' + +export default defineConfig([ + tseslint.configs.recommended, + { + files: ['**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + plugins: {js}, + extends: ['js/recommended'], + languageOptions: {globals: {...globals.browser, ...globals.node}} + }, + globalIgnores(['dist']) +]) diff --git a/package.json b/package.json new file mode 100644 index 0000000..9bc68c1 --- /dev/null +++ b/package.json @@ -0,0 +1,35 @@ +{ + "scripts": { + "check": "clear ; npm run typecheck && npm run lint && npx prettier -c **/*.{js,jsx,ts,tsx} && clear && echo 'OK'", + "fmt": "prettier --write **/*.{js,jsx,ts,tsx}", + "lint": "eslint **/*.{js,jsx,ts,tsx}", + "test": "bun test", + "typecheck": "tsc --noEmit" + }, + + "dependencies": { + "log": "git+https://git.pband.ch/typescript/log.git" + }, + "devDependencies": { + "@eslint/js": "^9.35.0", + "@types/bun": "^1.2.21", + "bun": "^1.2.21", + "eslint": "^9.35.0", + "globals": "^16.4.0", + "jiti": "^2.5.1", + "prettier": "^3.6.2", + "typescript": "^5.9.2", + "typescript-eslint": "^8.43.0" + }, + + "name": "lib-template", + "description": "Template library for typescript projects", + "version": "1.0.0", + + "author": "Pascal Perrenoud ", + "type": "module", + "main": "./src/index.ts", + "exports": { + ".": "./src/index.ts" + } +} diff --git a/src/env.ts b/src/env.ts new file mode 100644 index 0000000..50d4ae5 --- /dev/null +++ b/src/env.ts @@ -0,0 +1,38 @@ +import logger from 'log' +import fs from 'node:fs/promises' + +import type {Ok} from './helpers' + +const log = logger('config:env') +const FILE_EXT = "__FILE" + +// Read from env or file +export async function read_env(key: string): Promise> { + const path = process.env[key + FILE_EXT] + if (path !== undefined) return from_file(path) + else return {ok: true, data: process.env[key]} +} +async function from_file(path: string): Promise> { + log.debug("Read a key from a file") + log.trace("Path :", path) + + let content = await get_file_content(path) + if (!content.ok) return content + + content.data = content.data.trim() + + return content +} +async function get_file_content(path: string) : Promise> { + log.debug('Read file content') + log.trace('Path :', path) + + try { + const data = await fs.readFile(path, {encoding: 'utf-8'}) + return {ok: true, data} + } catch (e) { + log.warn('Failed to read file', path) + log.debug('Error :', e) + return {ok: false} + } +} diff --git a/src/helpers.ts b/src/helpers.ts new file mode 100644 index 0000000..b73984f --- /dev/null +++ b/src/helpers.ts @@ -0,0 +1 @@ +export type Ok = {ok: true, data: T} | {ok: false} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..3fbfcd6 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,17 @@ +import logger from 'log' + +import {Ok} from './helpers' + +// TODO : re-export types used to describe schema + +const log = logger('config') + +export async function parse(schema: S): Promise> { + log.info("Parse configuration from env") + + // TODO : Read config from env + + // TODO : maybe double check config + + return {ok: false} +} diff --git a/test/example.test.ts b/test/example.test.ts new file mode 100644 index 0000000..54e69fb --- /dev/null +++ b/test/example.test.ts @@ -0,0 +1,3 @@ +import {test} from 'bun:test' + +test('Basic test', () => 'Hello, world!') diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..5dc8e0f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "node", + "declaration": true, + "outDir": "dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true + }, + "include": ["src"] +}