@subf/config 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,153 @@
1
+ # @subf/config
2
+
3
+ Universal configuration for TypeScript, SolidJS, oxlint, and oxfmt.
4
+
5
+ ## Quick start
6
+
7
+ ```sh
8
+ bun i -D @subf/config
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### `tsconfig`
14
+
15
+ ```json
16
+ {
17
+ "extends": "@subf/config/tsc-lib"
18
+ }
19
+ ```
20
+
21
+ Available configs:
22
+
23
+ - `tsc-lib`: for libraries.
24
+ - `tsc-node`: for Node.js apps.
25
+ - `tsc-web`: for SolidJS apps.
26
+ - `tsc-base`: base config for custom setups.
27
+
28
+ ### `tsdown`
29
+
30
+ Helpers to create `tsdown` build configs.
31
+
32
+ Example: use `lib()` in your `tsdown.config.ts`:
33
+
34
+ ```ts
35
+ import { defineConfig } from 'tsdown'
36
+ import { lib } from '@subf/config/tsdown'
37
+
38
+ export default lib({
39
+ entry: 'shallow',
40
+ excludeDeps: ['oxlint', 'oxfmt', 'tsdown'],
41
+ overrides: {
42
+ exports: {
43
+ customExports(exports) {
44
+ exports['./custom'] = './you-custom-file.js'
45
+ return exports
46
+ },
47
+ },
48
+ },
49
+ })
50
+ ```
51
+
52
+ For Node builds use `nodeLib()`:
53
+
54
+ ```ts
55
+ import { nodeLib } from '@subf/config/tsdown'
56
+ export default nodeLib({ entry: 'src/index.ts' })
57
+ ```
58
+
59
+ For Solid builds (requires `vite-plugin-solid`) use `solidLib()`:
60
+
61
+ ```ts
62
+ import { defineConfig } from 'tsdown'
63
+ import { solidLib } from '@subf/config/tsdown'
64
+
65
+ export default solidLib({ entry: 'src/index.tsx' })
66
+ ```
67
+
68
+ ### `oxfmt`
69
+
70
+ In `oxfmt.config.ts`:
71
+
72
+ ```ts
73
+ import { CONFIG } from '@subf/config/oxfmt'
74
+ export default CONFIG
75
+ ```
76
+
77
+ #### Helper
78
+
79
+ Use `subfFmt()` helper to create a config with opinionated presets for lib, solid, unocss, etc.
80
+
81
+ ```ts
82
+ import { subfFmt } from '@subf/config/oxfmt'
83
+ export default subfFmt({
84
+ // your custom oxfmt config here
85
+ })
86
+ ```
87
+
88
+ ### `oxlint`
89
+
90
+ In `oxlint.config.ts`:
91
+
92
+ ```ts
93
+ import { CONFIG } from '@subf/config/oxlint'
94
+
95
+ export default CONFIG
96
+ ```
97
+
98
+ or use `defineConfig()` with `extend` if you want to extend it:
99
+
100
+ ```ts
101
+ import { defineConfig } from 'oxlint'
102
+ import { CONFIG } from '@subf/config/oxlint'
103
+
104
+ export default defineConfig({
105
+ extend: [CONFIG],
106
+ // your custom config here
107
+ })
108
+ ```
109
+
110
+ #### Helper
111
+
112
+ Use `subf()` helper to create a config with opinionated presets for lib, solid, unocss, etc.
113
+
114
+ ```ts
115
+ import { subf } from '@subf/config/oxlint'
116
+
117
+ export default subf({
118
+ lib: true,
119
+ solid: true,
120
+ unocss: true,
121
+ // your custom oxlint config here
122
+ })
123
+ ```
124
+
125
+ ## CLI
126
+
127
+ Scaffold `tsconfig.json`, `oxlint.config.ts`, and `oxfmt.config.ts` into your project.
128
+
129
+ ### Quick start (no install)
130
+
131
+ ```sh
132
+ bunx @subf/config # recommended
133
+ npx -y @subf/config # fallback
134
+ bunx @subf/config -f # force overwrite existing files
135
+ ```
136
+
137
+ After scaffolding you'll be prompted to install the package so your configs stay in sync with future updates:
138
+
139
+ ```sh
140
+ bun i -D @subf/config
141
+ ```
142
+
143
+ ### Installed locally
144
+
145
+ ```sh
146
+ bun i -D @subf/config
147
+ bun subf # or just `subf` if on PATH
148
+ bun subf -f # force overwrite existing files
149
+ ```
150
+
151
+ ## License
152
+
153
+ MIT
package/bin/subf.js ADDED
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs'
3
+ import path from 'node:path'
4
+ import { fileURLToPath } from 'node:url'
5
+
6
+ export function createConfigs({ cwd = process.cwd(), force = false } = {}) {
7
+ const files = [
8
+ {
9
+ name: 'oxfmt.config.ts',
10
+ content: "import { subfFmt } from '@subf/config/oxfmt'\n\nexport default subfFmt()\n",
11
+ },
12
+ {
13
+ name: 'oxlint.config.ts',
14
+ content: "import { subfLint } from '@subf/config/oxlint'\n\nexport default subfLint()\n",
15
+ },
16
+ {
17
+ name: 'tsconfig.json',
18
+ content: `${JSON.stringify({ extends: '@subf/config/tsconfig-lib' }, null, 2)}\n`,
19
+ },
20
+ ]
21
+
22
+ const created = []
23
+
24
+ for (const file of files) {
25
+ const full = path.join(cwd, file.name)
26
+ if (existsSync(full) && !force) {
27
+ console.log(`Skipped ${file.name} (exists). Use --force to overwrite.`)
28
+ continue
29
+ }
30
+
31
+ writeFileSync(full, file.content, 'utf8')
32
+ created.push(file.name)
33
+ console.log(`Wrote ${file.name}`)
34
+ }
35
+
36
+ if (created.length === 0) {
37
+ console.log('No files created.')
38
+ } else {
39
+ console.log('Created:', created.join(', '))
40
+ }
41
+
42
+ return created
43
+ }
44
+
45
+ // If invoked directly, run with CLI args
46
+ if (fileURLToPath(import.meta.url) === process.argv[1]) {
47
+ const projectRoot = process.env.INIT_CWD || process.cwd()
48
+ const args = new Set(process.argv.slice(2))
49
+ const force = args.has('--force') || args.has('-f')
50
+ const help = args.has('--help') || args.has('-h')
51
+
52
+ if (help) {
53
+ console.log('Usage: subf [-f|--force]')
54
+ console.log('Create helper config files in the current project:')
55
+ console.log(' oxfmt.config.ts, oxlint.config.ts, tsconfig.json')
56
+ console.log('Use -f or --force to overwrite existing files.')
57
+ process.exit(0)
58
+ }
59
+
60
+ try {
61
+ createConfigs({ cwd: projectRoot, force })
62
+ } catch (err) {
63
+ console.error('Failed to create config files:', err)
64
+ process.exit(1)
65
+ }
66
+
67
+ // If project has package.json, suggest installing @subf/config when it's not listed
68
+ const projectPkgPath = path.join(projectRoot, 'package.json')
69
+ if (!existsSync(projectPkgPath)) {
70
+ console.log('No package.json found in project root.')
71
+ console.log('To keep these configs in sync, install @subf/config as a devDependency:')
72
+ console.log(' bun i -D @subf/config')
73
+ console.log(' npm i -D @subf/config')
74
+ process.exit(0)
75
+ }
76
+
77
+ let projectPkg
78
+ try {
79
+ projectPkg = JSON.parse(readFileSync(projectPkgPath, 'utf8'))
80
+ } catch (err) {
81
+ console.log(
82
+ 'Created helper configs. Could not read package.json to suggest install command.',
83
+ err && (err.message || err),
84
+ )
85
+ process.exit(0)
86
+ }
87
+
88
+ const hasDep =
89
+ (projectPkg.devDependencies && projectPkg.devDependencies['@subf/config']) ||
90
+ (projectPkg.dependencies && projectPkg.dependencies['@subf/config'])
91
+
92
+ if (hasDep) {
93
+ console.log('Helper configs created. @subf/config is present in package.json.')
94
+ } else {
95
+ console.log(
96
+ 'Helper configs created. To keep them in sync, install @subf/config as a devDependency:',
97
+ )
98
+ console.log(' bun i -D @subf/config')
99
+ console.log(' npm i -D @subf/config')
100
+ }
101
+
102
+ process.exit(0)
103
+ }
@@ -0,0 +1,7 @@
1
+ import { OxfmtConfig } from "oxfmt";
2
+
3
+ //#region src/oxfmt.d.ts
4
+ declare const CONFIG: OxfmtConfig;
5
+ declare function subfFmt(config?: OxfmtConfig): OxfmtConfig;
6
+ //#endregion
7
+ export { CONFIG, CONFIG as default, subfFmt };
package/dist/oxfmt.js ADDED
@@ -0,0 +1,22 @@
1
+ //#region src/oxfmt.ts
2
+ const CONFIG = {
3
+ semi: false,
4
+ singleQuote: true,
5
+ sortImports: { groups: [
6
+ ["side_effect"],
7
+ ["builtin"],
8
+ ["external", "type-external"],
9
+ ["internal", "type-internal"],
10
+ ["parent", "type-parent"],
11
+ ["sibling", "type-sibling"],
12
+ ["index", "type-index"]
13
+ ] }
14
+ };
15
+ function subfFmt(config) {
16
+ return {
17
+ ...CONFIG,
18
+ ...config
19
+ };
20
+ }
21
+ //#endregion
22
+ export { CONFIG, CONFIG as default, subfFmt };
@@ -0,0 +1,24 @@
1
+ import { OxlintConfig, OxlintOverride } from "oxlint";
2
+
3
+ //#region src/oxlint.d.ts
4
+ declare const baseConfig: OxlintConfig;
5
+ declare const baseRules: OxlintConfig;
6
+ declare const FILES_TS_TSX: string[];
7
+ declare const ts: OxlintOverride;
8
+ declare const vitest: OxlintOverride;
9
+ declare const markdownOverrideConfig: OxlintOverride;
10
+ declare const overrides: OxlintOverride[];
11
+ declare const CONFIG: OxlintConfig;
12
+ declare const unocss: OxlintOverride;
13
+ declare const solid: OxlintOverride;
14
+ interface SubfOpions extends OxlintConfig {
15
+ /**
16
+ * Used for lib, force to explicit function return type
17
+ */
18
+ lib?: boolean;
19
+ solid?: boolean;
20
+ unocss?: boolean;
21
+ }
22
+ declare function subfLint(options?: SubfOpions): OxlintConfig;
23
+ //#endregion
24
+ export { CONFIG, CONFIG as default, FILES_TS_TSX, SubfOpions, baseConfig, baseRules, markdownOverrideConfig, overrides, solid, subfLint, ts, unocss, vitest };
package/dist/oxlint.js ADDED
@@ -0,0 +1,434 @@
1
+ //#region src/oxlint.ts
2
+ const baseConfig = {
3
+ env: {
4
+ builtin: true,
5
+ browser: true,
6
+ es2024: true,
7
+ node: true
8
+ },
9
+ globals: {
10
+ AudioWorkletGlobalScope: "readonly",
11
+ AudioWorkletProcessor: "readonly",
12
+ currentFrame: "readonly",
13
+ currentTime: "readonly",
14
+ registerProcessor: "readonly",
15
+ sampleRate: "readonly",
16
+ WorkletGlobalScope: "readonly"
17
+ },
18
+ ignorePatterns: [
19
+ "**/logs",
20
+ "**/*.log",
21
+ "**/npm-debug.log*",
22
+ "**/yarn-debug.log*",
23
+ "**/yarn-error.log*",
24
+ "**/pids",
25
+ "**/*.pid",
26
+ "**/*.seed",
27
+ "**/*.pid.lock",
28
+ "**/lib-cov",
29
+ "**/coverage",
30
+ "**/.nyc_output",
31
+ "**/.grunt",
32
+ "**/bower_components",
33
+ "**/.lock-wscript",
34
+ "build/Release",
35
+ "**/node_modules/",
36
+ "**/jspm_packages/",
37
+ "**/typings/",
38
+ "**/.npm",
39
+ "**/.eslintcache",
40
+ "**/.node_repl_history",
41
+ "**/*.tgz",
42
+ "**/.yarn-integrity",
43
+ "**/.env",
44
+ "**/.cache",
45
+ "**/.next",
46
+ "**/.nuxt",
47
+ "**/dist",
48
+ "**/.serverless",
49
+ "**/.idea",
50
+ "**/*.lerna_backup",
51
+ "**/_fixtures",
52
+ "**/.temp",
53
+ "**/.history",
54
+ "**/.eslint-config-inspector",
55
+ "**/node_modules",
56
+ "**/package-lock.json",
57
+ "**/yarn.lock",
58
+ "**/pnpm-lock.yaml",
59
+ "**/bun.lockb",
60
+ "**/output",
61
+ "**/temp",
62
+ "**/tmp",
63
+ "**/.tmp",
64
+ "**/.vitepress/cache",
65
+ "**/.svelte-kit",
66
+ "**/.vercel",
67
+ "**/.changeset",
68
+ "**/.output",
69
+ "**/.vite-inspect",
70
+ "**/.yarn",
71
+ "**/vite.config.*.timestamp-*",
72
+ "**/CHANGELOG*.md",
73
+ "**/*.min.*",
74
+ "**/LICENSE*",
75
+ "**/__snapshots__",
76
+ "**/auto-import?(s).d.ts",
77
+ "**/components.d.ts",
78
+ "_fixtures"
79
+ ]
80
+ };
81
+ const baseRules = {
82
+ plugins: [
83
+ "node",
84
+ "jsdoc",
85
+ "import",
86
+ "unicorn",
87
+ "oxc",
88
+ "typescript",
89
+ "eslint"
90
+ ],
91
+ categories: { correctness: "error" },
92
+ rules: {
93
+ "array-callback-return": "error",
94
+ "block-scoped-var": "error",
95
+ "class-methods-use-this": "error",
96
+ "constructor-super": "error",
97
+ curly: ["error", "all"],
98
+ "default-case-last": "error",
99
+ "default-param-last": "error",
100
+ eqeqeq: ["error", "smart"],
101
+ "new-cap": ["error", {
102
+ capIsNew: false,
103
+ newIsCap: true,
104
+ properties: true
105
+ }],
106
+ "no-alert": "error",
107
+ "no-array-constructor": "error",
108
+ "no-async-promise-executor": "error",
109
+ "no-constant-binary-expression": "error",
110
+ "no-caller": "error",
111
+ "no-case-declarations": "error",
112
+ "no-class-assign": "error",
113
+ "no-compare-neg-zero": "error",
114
+ "no-cond-assign": ["error", "always"],
115
+ "no-const-assign": "error",
116
+ "no-control-regex": "error",
117
+ "no-debugger": "error",
118
+ "no-delete-var": "error",
119
+ "no-dupe-class-members": "error",
120
+ "no-dupe-keys": "error",
121
+ "no-duplicate-case": "error",
122
+ "no-empty": ["error", { allowEmptyCatch: true }],
123
+ "no-empty-pattern": "error",
124
+ "no-eq-null": "error",
125
+ "no-eval": "error",
126
+ "no-ex-assign": "error",
127
+ "no-extend-native": "error",
128
+ "no-extra-bind": "error",
129
+ "no-extra-boolean-cast": "error",
130
+ "no-fallthrough": "error",
131
+ "no-func-assign": "error",
132
+ "no-global-assign": "error",
133
+ "no-import-assign": "error",
134
+ "no-inner-declarations": [
135
+ "error",
136
+ "functions",
137
+ "disallow"
138
+ ],
139
+ "no-irregular-whitespace": "error",
140
+ "no-iterator": "error",
141
+ "no-labels": ["error", {
142
+ allowLoop: false,
143
+ allowSwitch: false
144
+ }],
145
+ "no-lone-blocks": "error",
146
+ "no-loss-of-precision": "error",
147
+ "no-misleading-character-class": "error",
148
+ "no-multi-str": "error",
149
+ "no-new": "error",
150
+ "no-new-func": "error",
151
+ "no-new-native-nonconstructor": "error",
152
+ "no-new-wrappers": "error",
153
+ "no-obj-calls": "error",
154
+ "no-proto": "error",
155
+ "no-prototype-builtins": "error",
156
+ "no-redeclare": ["error", { builtinGlobals: false }],
157
+ "no-regex-spaces": "error",
158
+ "no-restricted-globals": [
159
+ "error",
160
+ {
161
+ message: "Use `globalThis` instead.",
162
+ name: "global"
163
+ },
164
+ {
165
+ message: "Use `globalThis` instead.",
166
+ name: "self"
167
+ }
168
+ ],
169
+ "no-self-assign": ["error", { props: true }],
170
+ "no-self-compare": "error",
171
+ "no-shadow-restricted-names": "error",
172
+ "no-sparse-arrays": "error",
173
+ "no-template-curly-in-string": "error",
174
+ "no-this-before-super": "error",
175
+ "no-throw-literal": "error",
176
+ "no-unexpected-multiline": "error",
177
+ "no-unmodified-loop-condition": "error",
178
+ "no-unneeded-ternary": ["error", { defaultAssignment: false }],
179
+ "no-unreachable": "error",
180
+ "no-unsafe-finally": "error",
181
+ "no-unsafe-negation": "error",
182
+ "no-unused-expressions": ["error", {
183
+ allowShortCircuit: true,
184
+ allowTaggedTemplates: true,
185
+ allowTernary: true
186
+ }],
187
+ "no-use-before-define": ["error", {
188
+ classes: false,
189
+ functions: false,
190
+ variables: true
191
+ }],
192
+ "no-useless-call": "error",
193
+ "no-useless-catch": "error",
194
+ "no-useless-computed-key": "error",
195
+ "no-useless-constructor": "error",
196
+ "no-useless-rename": "error",
197
+ "no-useless-return": "error",
198
+ "no-var": "error",
199
+ "no-with": "error",
200
+ "no-empty-character-class": "error",
201
+ "no-constructor-return": "error",
202
+ "no-unused-vars": "error",
203
+ "no-nonoctal-decimal-escape": "error",
204
+ "no-setter-return": "error",
205
+ "no-unused-labels": "error",
206
+ "no-dupe-else-if": "error",
207
+ "no-invalid-regexp": "error",
208
+ "no-constant-condition": "error",
209
+ "no-useless-escape": "error",
210
+ "no-unsafe-optional-chaining": "error",
211
+ "prefer-exponentiation-operator": "error",
212
+ "prefer-rest-params": "error",
213
+ "prefer-spread": "error",
214
+ "prefer-template": "error",
215
+ "symbol-description": "error",
216
+ "unicode-bom": ["error", "never"],
217
+ "use-isnan": ["error", {
218
+ enforceForIndexOf: true,
219
+ enforceForSwitchCase: true
220
+ }],
221
+ "valid-typeof": ["error", { requireStringLiterals: true }],
222
+ "vars-on-top": "error",
223
+ yoda: ["error", "never"],
224
+ "node/handle-callback-err": ["error", "^(err|error)$"],
225
+ "node/no-exports-assign": "error",
226
+ "node/no-new-require": "error",
227
+ "node/no-path-concat": "error",
228
+ "jsdoc/check-access": "warn",
229
+ "jsdoc/check-property-names": "warn",
230
+ "jsdoc/empty-tags": "warn",
231
+ "jsdoc/implements-on-classes": "warn",
232
+ "jsdoc/no-defaults": "warn",
233
+ "jsdoc/require-param-name": "warn",
234
+ "jsdoc/require-property": "warn",
235
+ "jsdoc/require-property-description": "warn",
236
+ "jsdoc/require-property-name": "warn",
237
+ "jsdoc/require-returns-description": "warn",
238
+ "unicorn/consistent-empty-array-spread": "error",
239
+ "unicorn/error-message": "error",
240
+ "unicorn/escape-case": "error",
241
+ "unicorn/new-for-builtins": "error",
242
+ "unicorn/no-instanceof-builtins": "error",
243
+ "unicorn/no-instanceof-array": "error",
244
+ "unicorn/no-new-array": "allow",
245
+ "unicorn/no-new-buffer": "error",
246
+ "unicorn/number-literal-case": "error",
247
+ "unicorn/prefer-array-find": "error",
248
+ "unicorn/prefer-array-flat-map": "error",
249
+ "unicorn/prefer-array-some": "error",
250
+ "unicorn/prefer-code-point": "error",
251
+ "unicorn/prefer-date-now": "error",
252
+ "unicorn/prefer-dom-node-text-content": "error",
253
+ "unicorn/prefer-includes": "error",
254
+ "unicorn/prefer-node-protocol": "error",
255
+ "unicorn/prefer-number-properties": "error",
256
+ "unicorn/prefer-string-starts-ends-with": "error",
257
+ "unicorn/prefer-type-error": "error",
258
+ "unicorn/throw-new-error": "error",
259
+ "unicorn/prefer-set-has": "error",
260
+ "import/consistent-type-specifier-style": "error",
261
+ "import/no-absolute-path": "error",
262
+ "import/no-duplicates": "error",
263
+ "import/no-self-import": "error",
264
+ "import/no-named-export": "allow",
265
+ "import/first": "error",
266
+ "oxc/no-map-spread": "error",
267
+ "oxc/misrefactored-assign-op": "error",
268
+ "oxc/no-this-in-exported-function": "error"
269
+ }
270
+ };
271
+ const FILES_TS_TSX = ["**/*.{ts,tsx}"];
272
+ const ts = {
273
+ files: FILES_TS_TSX,
274
+ plugins: ["typescript"],
275
+ jsPlugins: [{
276
+ name: "subf",
277
+ specifier: "@subf/oxlint-plugin"
278
+ }],
279
+ rules: {
280
+ "subf/method-signature-style": ["error", "property"],
281
+ "constructor-super": "off",
282
+ "no-class-assign": "off",
283
+ "no-const-assign": "off",
284
+ "no-dupe-keys": "off",
285
+ "no-func-assign": "off",
286
+ "no-import-assign": "off",
287
+ "no-new-native-nonconstructor": "off",
288
+ "no-obj-calls": "off",
289
+ "no-redeclare": ["error", { builtinGlobals: false }],
290
+ "no-setter-return": "off",
291
+ "no-this-before-super": "off",
292
+ "no-unsafe-negation": "off",
293
+ "no-with": "off",
294
+ "no-unused-expressions": ["error", {
295
+ allowShortCircuit: true,
296
+ allowTaggedTemplates: true,
297
+ allowTernary: true
298
+ }],
299
+ "no-useless-constructor": "off",
300
+ "no-use-before-define": ["error", {
301
+ classes: false,
302
+ functions: false,
303
+ variables: true
304
+ }],
305
+ "typescript/ban-ts-comment": ["error", { "ts-expect-error": "allow-with-description" }],
306
+ "typescript/no-duplicate-enum-values": "error",
307
+ "typescript/no-extra-non-null-assertion": "error",
308
+ "typescript/no-misused-new": "error",
309
+ "typescript/no-non-null-asserted-nullish-coalescing": "error",
310
+ "typescript/no-non-null-asserted-optional-chain": "error",
311
+ "typescript/no-require-imports": "error",
312
+ "typescript/no-this-alias": "error",
313
+ "typescript/no-unnecessary-type-constraint": "error",
314
+ "typescript/no-unnecessary-type-assertion": "error",
315
+ "typescript/no-unsafe-declaration-merging": "error",
316
+ "typescript/no-unsafe-function-type": "error",
317
+ "typescript/no-wrapper-object-types": "error",
318
+ "typescript/prefer-as-const": "error",
319
+ "typescript/prefer-literal-enum-member": "error",
320
+ "typescript/prefer-namespace-keyword": "error",
321
+ "typescript/prefer-ts-expect-error": "error",
322
+ "typescript/switch-exhaustiveness-check": "error",
323
+ "typescript/consistent-type-imports": ["error", {
324
+ disallowTypeAnnotations: false,
325
+ prefer: "type-imports"
326
+ }],
327
+ "typescript/no-import-type-side-effects": "error",
328
+ "typescript/no-unnecessary-type-arguments": "error"
329
+ }
330
+ };
331
+ const vitest = {
332
+ files: [
333
+ "**/__tests__/**/*.?([cm])[jt]s?(x)",
334
+ "**/*.spec.?([cm])[jt]s?(x)",
335
+ "**/*.test.?([cm])[jt]s?(x)",
336
+ "**/*.bench.?([cm])[jt]s?(x)",
337
+ "**/*.benchmark.?([cm])[jt]s?(x)"
338
+ ],
339
+ plugins: ["vitest"],
340
+ rules: {
341
+ "vitest/consistent-test-it": ["error", {
342
+ fn: "it",
343
+ withinDescribe: "it"
344
+ }],
345
+ "vitest/no-identical-title": "error",
346
+ "vitest/no-import-node-test": "error",
347
+ "vitest/prefer-hooks-in-order": "error",
348
+ "vitest/prefer-lowercase-title": "error",
349
+ "no-unused-expressions": "off"
350
+ }
351
+ };
352
+ const markdownOverrideConfig = {
353
+ files: ["**/*.md/**/*.?([cm])[jt]s?(x)"],
354
+ rules: {
355
+ "no-alert": "off",
356
+ "no-labels": "off",
357
+ "no-lone-blocks": "off",
358
+ "no-unused-expressions": "off",
359
+ "no-unused-labels": "off",
360
+ "unicode-bom": "off"
361
+ }
362
+ };
363
+ const overrides = [
364
+ ts,
365
+ vitest,
366
+ markdownOverrideConfig
367
+ ];
368
+ const CONFIG = {
369
+ ...baseConfig,
370
+ ...baseRules,
371
+ overrides
372
+ };
373
+ const unocss = {
374
+ files: FILES_TS_TSX,
375
+ jsPlugins: [{
376
+ name: "uno",
377
+ specifier: "@unocss/eslint-plugin"
378
+ }],
379
+ rules: {
380
+ "uno/order": ["warn", { unoFunctions: ["cn", "cva"] }],
381
+ "uno/blocklist": "error"
382
+ }
383
+ };
384
+ const solid = {
385
+ files: FILES_TS_TSX,
386
+ jsPlugins: ["eslint-plugin-solid"],
387
+ rules: {
388
+ "solid/event-handlers": ["error", {
389
+ ignoreCase: false,
390
+ warnOnSpread: false
391
+ }],
392
+ "solid/imports": "error",
393
+ "solid/jsx-no-duplicate-props": "error",
394
+ "solid/jsx-no-script-url": "error",
395
+ "solid/no-destructure": "error",
396
+ "solid/no-innerhtml": ["error", { allowStatic: true }],
397
+ "solid/no-react-deps": "error",
398
+ "solid/no-react-specific-props": "error",
399
+ "solid/no-unknown-namespaces": "error",
400
+ "solid/prefer-for": "error",
401
+ "solid/prefer-show": "error",
402
+ "solid/self-closing-comp": "error",
403
+ "solid/style-prop": ["error", { styleProps: ["style", "css"] }],
404
+ "solid/jsx-no-undef": ["error", { typescriptEnabled: true }],
405
+ "solid/reactivity": "warn"
406
+ }
407
+ };
408
+ function subfLint(options = {}) {
409
+ const { lib, unocss: enableUnocss, solid: enableSolid, overrides: customOverrides = [], ...oxlint } = options;
410
+ const ovr = [vitest, markdownOverrideConfig];
411
+ if (lib) ovr.push({
412
+ ...ts,
413
+ rules: {
414
+ ...ts.rules,
415
+ "typescript/explicit-function-return-type": ["error", {
416
+ allowExpressions: true,
417
+ allowTypedFunctionExpressions: true,
418
+ allowIIFEs: true
419
+ }]
420
+ }
421
+ });
422
+ else ovr.push(ts);
423
+ if (enableUnocss) ovr.push(unocss);
424
+ if (enableSolid) ovr.push(solid);
425
+ ovr.push(...customOverrides);
426
+ return {
427
+ ...baseConfig,
428
+ ...baseRules,
429
+ ...oxlint,
430
+ overrides: ovr
431
+ };
432
+ }
433
+ //#endregion
434
+ export { CONFIG, CONFIG as default, FILES_TS_TSX, baseConfig, baseRules, markdownOverrideConfig, overrides, solid, subfLint, ts, unocss, vitest };
@@ -0,0 +1,46 @@
1
+ import { DepsConfig, ExportsOptions, TsdownInputOption, UserConfig } from "tsdown";
2
+
3
+ //#region src/tsdown.d.ts
4
+ interface LibOptions {
5
+ /**
6
+ * The entry point for the library.
7
+ * - 'index' (default): Only include `src/index.ts`.
8
+ * - 'shallow': Include all `.ts` files directly under `src/`.
9
+ * - 'all': Include all `.ts` files under `src/` recursively.
10
+ * - Custom glob pattern or array of file paths.
11
+ *
12
+ * @default 'index'
13
+ */
14
+ entry?: "index" | "shallow" | "all" | Exclude<TsdownInputOption, string>;
15
+ /**
16
+ * tsdown's `customExports` option, which controls how the exports field is generated in package.json.
17
+ *
18
+ * @default true
19
+ */
20
+ extraExports?: ExportsOptions["customExports"];
21
+ /**
22
+ * tsdown's deps option, which controls how dependencies are bundled / excluded.
23
+ */
24
+ bundled?: DepsConfig["alwaysBundle"];
25
+ unbundled?: DepsConfig["neverBundle"];
26
+ overrides?: UserConfig;
27
+ }
28
+ declare function lib(options?: LibOptions): UserConfig;
29
+ declare function nodeLib(options?: LibOptions): UserConfig;
30
+ interface SolidLibOptions extends LibOptions {
31
+ /**
32
+ * Options to pass to the `vite-plugin-solid` plugin. This is useful if you want to customize the solid plugin options, such as enabling hot module replacement (HMR) or configuring the Solid compiler.
33
+ */
34
+ solid?: Record<string, any>;
35
+ /**
36
+ * Overrides for the js output config. This is useful if you want to customize the js output config, such as adding additional plugins or changing the output format.
37
+ */
38
+ jsOverride?: UserConfig;
39
+ /**
40
+ * Overrides for the jsx output config. This is useful if you want to customize the jsx output config, such as adding additional plugins or changing the output format.
41
+ */
42
+ jsxOverride?: UserConfig;
43
+ }
44
+ declare function solidLib(options: SolidLibOptions): Promise<UserConfig[]>;
45
+ //#endregion
46
+ export { SolidLibOptions, lib, nodeLib, solidLib };
package/dist/tsdown.js ADDED
@@ -0,0 +1,62 @@
1
+ import { mergeConfig } from "tsdown/config";
2
+ //#region src/tsdown.ts
3
+ function lib(options = {}) {
4
+ const { entry = "index", extraExports, bundled, unbundled, overrides = {} } = options;
5
+ return mergeConfig({
6
+ entry: entry === "index" ? "src/index.ts" : entry === "shallow" ? "src/*.ts" : entry === "all" ? "src/**/*.ts" : entry,
7
+ dts: { oxc: true },
8
+ platform: "neutral",
9
+ deps: {
10
+ alwaysBundle: bundled,
11
+ neverBundle: unbundled
12
+ },
13
+ exports: { customExports: extraExports }
14
+ }, overrides);
15
+ }
16
+ function nodeLib(options = {}) {
17
+ return lib({
18
+ ...options,
19
+ overrides: {
20
+ platform: "node",
21
+ ...options.overrides
22
+ }
23
+ });
24
+ }
25
+ async function loadSolidPlugin(options) {
26
+ let solid;
27
+ try {
28
+ solid = await import("vite-plugin-solid").then((m) => m.default || m);
29
+ } catch {
30
+ throw new Error("`vite-plugin-solid` is required for solidLib.");
31
+ }
32
+ return solid(options);
33
+ }
34
+ async function solidLib(options) {
35
+ const { entry, solid: solidOptions, extraExports, overrides = {}, jsOverride = {}, jsxOverride = {} } = options;
36
+ return [mergeConfig({
37
+ entry,
38
+ platform: "browser",
39
+ plugins: [loadSolidPlugin(solidOptions)],
40
+ dts: true
41
+ }, overrides, jsOverride), mergeConfig({
42
+ entry,
43
+ platform: "neutral",
44
+ outExtensions: () => ({ js: ".jsx" }),
45
+ dts: false,
46
+ exports: { customExports(exports, context) {
47
+ for (const [key, val] of Object.entries(exports)) if (val.endsWith(".jsx")) exports[key] = {
48
+ solid: val,
49
+ default: val.replace(".jsx", ".mjs"),
50
+ type: val.replace(".jsx", ".d.mts")
51
+ };
52
+ if (!extraExports) return exports;
53
+ else if (typeof extraExports === "function") return extraExports(exports, context);
54
+ else return {
55
+ ...exports,
56
+ ...extraExports
57
+ };
58
+ } }
59
+ }, overrides, jsxOverride)];
60
+ }
61
+ //#endregion
62
+ export { lib, nodeLib, solidLib };
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@subf/config",
3
+ "version": "0.0.0",
4
+ "description": "Universal configuration for TypeScript, SolidJS, oxlint, oxfmt",
5
+ "homepage": "https://github.com/subframe7536/config#readme",
6
+ "bugs": {
7
+ "url": "https://github.com/subframe7536/config/issues"
8
+ },
9
+ "license": "MIT",
10
+ "author": "subframe7536",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/subframe7536/config.git"
14
+ },
15
+ "bin": {
16
+ "subf": "./bin/subf.js"
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "tsconfig.*.json",
21
+ "bin"
22
+ ],
23
+ "type": "module",
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "exports": {
28
+ "./oxfmt": "./dist/oxfmt.js",
29
+ "./oxlint": "./dist/oxlint.js",
30
+ "./tsdown": "./dist/tsdown.js",
31
+ "./package.json": "./package.json",
32
+ "./tsconfig-base": "./tsconfig.base.json",
33
+ "./tsconfig-node": "./tsconfig.node.json",
34
+ "./tsconfig-web": "./tsconfig.web.json",
35
+ "./tsconfig-lib": "./tsconfig.lib.json"
36
+ },
37
+ "scripts": {
38
+ "build": "tsdown",
39
+ "dev": "tsdown --watch",
40
+ "typecheck": "tsc --noEmit",
41
+ "release": "node --test && bumpp --all",
42
+ "qa": "oxlint --fix && oxfmt",
43
+ "prepublishOnly": "bun run build",
44
+ "test": "node --test"
45
+ },
46
+ "dependencies": {
47
+ "@subf/oxlint-plugin": "^0.1.0"
48
+ },
49
+ "devDependencies": {
50
+ "@oxlint/plugins": "^1.58.0",
51
+ "@types/bun": "^1.3.11",
52
+ "bumpp": "^11.0.1",
53
+ "oxfmt": "^0.43.0",
54
+ "oxlint": "^1.58.0",
55
+ "tsdown": "^0.21.7",
56
+ "typescript": "^5.9.3"
57
+ }
58
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "esnext",
4
+ "module": "esnext",
5
+ "lib": ["ESNext"],
6
+ "resolveJsonModule": true,
7
+ "strict": true,
8
+ "strictNullChecks": true,
9
+ "noUnusedLocals": true,
10
+ "noUncheckedIndexedAccess": true,
11
+ "noImplicitOverride": true,
12
+ "esModuleInterop": true,
13
+ "isolatedModules": true,
14
+ "verbatimModuleSyntax": true,
15
+ "skipLibCheck": true,
16
+ "declaration": true,
17
+ "sourceMap": true,
18
+ "noEmit": true
19
+ }
20
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "extends": "./tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "moduleResolution": "bundler"
5
+ }
6
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "./tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "lib": ["ESNext"],
5
+ "module": "nodenext",
6
+ "moduleResolution": "nodenext",
7
+ "allowImportingTsExtensions": true
8
+ }
9
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "./tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "moduleResolution": "bundler",
5
+ "jsx": "preserve",
6
+ "jsxImportSource": "solid-js",
7
+ "lib": ["DOM", "ESNext", "DOM.Iterable"],
8
+ "types": ["vite/client"]
9
+ }
10
+ }