@rtorcato/repo-tooling 2.59.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/AGENTS.md +113 -0
- package/LICENSE +21 -0
- package/README.md +201 -0
- package/dist/cli/commands/doctor.js +336 -0
- package/dist/cli/commands/fix-targets.js +192 -0
- package/dist/cli/commands/fix.js +440 -0
- package/dist/cli/commands/setup-presets.js +281 -0
- package/dist/cli/commands/setup.js +501 -0
- package/dist/cli/generators/agent-rules.js +103 -0
- package/dist/cli/generators/badges.js +88 -0
- package/dist/cli/generators/build.js +216 -0
- package/dist/cli/generators/bun.js +25 -0
- package/dist/cli/generators/community-health.js +145 -0
- package/dist/cli/generators/docs-site.js +436 -0
- package/dist/cli/generators/git.js +164 -0
- package/dist/cli/generators/github-actions.js +35 -0
- package/dist/cli/generators/github-workflows.js +24 -0
- package/dist/cli/generators/gitlab-ci.js +10 -0
- package/dist/cli/generators/index.js +123 -0
- package/dist/cli/generators/linting.js +54 -0
- package/dist/cli/generators/misc.js +298 -0
- package/dist/cli/generators/nx.js +16 -0
- package/dist/cli/generators/package-json.js +317 -0
- package/dist/cli/generators/pnpm-workspace.js +126 -0
- package/dist/cli/generators/postcss.js +24 -0
- package/dist/cli/generators/readme.js +268 -0
- package/dist/cli/generators/security.js +156 -0
- package/dist/cli/generators/skills-install.js +70 -0
- package/dist/cli/generators/tailwind.js +34 -0
- package/dist/cli/generators/testing.js +88 -0
- package/dist/cli/generators/treeshake.js +148 -0
- package/dist/cli/generators/tsconfig.js +27 -0
- package/dist/cli/generators/turborepo.js +35 -0
- package/dist/cli/generators/typedoc.js +40 -0
- package/dist/cli/index.js +332 -0
- package/dist/cli/utils/copy-preset.js +98 -0
- package/dist/cli/utils/detect-language.js +22 -0
- package/dist/cli/utils/format.js +32 -0
- package/dist/cli/utils/install.js +28 -0
- package/dist/cli/utils/lockfile.js +84 -0
- package/dist/languages/js/checks.js +949 -0
- package/dist/languages/js/ci.js +251 -0
- package/dist/languages/js/fixers.js +735 -0
- package/dist/languages/registry.js +37 -0
- package/dist/languages/swift/checks.js +127 -0
- package/dist/languages/swift/ci.js +165 -0
- package/dist/languages/swift/fixers.js +102 -0
- package/dist/languages/swift/git-hooks.js +63 -0
- package/dist/languages/swift/gitignore.js +43 -0
- package/dist/languages/swift/scaffold.js +244 -0
- package/package.json +461 -0
- package/tooling/biome/README.md +90 -0
- package/tooling/biome/biome.json +63 -0
- package/tooling/bun/bunfig.toml +14 -0
- package/tooling/changesets/README.md +35 -0
- package/tooling/changesets/config.json +11 -0
- package/tooling/claude/repo-tooling.md +87 -0
- package/tooling/commitlint/commitlint.d.mts +4 -0
- package/tooling/commitlint/commitlint.mjs +40 -0
- package/tooling/cypress/cypress.config.d.mts +4 -0
- package/tooling/cypress/cypress.config.mjs +11 -0
- package/tooling/docusaurus/index.d.mts +17 -0
- package/tooling/docusaurus/index.mjs +38 -0
- package/tooling/docusaurus/sync-changelog.mjs +42 -0
- package/tooling/docusaurus/theme-tokens.css +79 -0
- package/tooling/docusaurus/theme.css +378 -0
- package/tooling/esbuild/index.d.mts +6 -0
- package/tooling/esbuild/index.mjs +102 -0
- package/tooling/eslint/base.d.mts +6 -0
- package/tooling/eslint/base.mjs +122 -0
- package/tooling/eslint/nextjs.d.mts +4 -0
- package/tooling/eslint/nextjs.mjs +22 -0
- package/tooling/eslint/types.d.ts +58 -0
- package/tooling/github-actions/workflows/cloudflare-pages.yml +42 -0
- package/tooling/github-actions/workflows/docker-publish.yml +44 -0
- package/tooling/github-actions/workflows/preview-deployments.yml +54 -0
- package/tooling/github-actions/workflows/vercel-deploy.yml +40 -0
- package/tooling/jest-presets/browser/jest-preset.d.mts +4 -0
- package/tooling/jest-presets/browser/jest-preset.mjs +14 -0
- package/tooling/jest-presets/node/jest-preset.d.mts +4 -0
- package/tooling/jest-presets/node/jest-preset.mjs +13 -0
- package/tooling/mcp/mcp.json.example +27 -0
- package/tooling/nx/nx.json +24 -0
- package/tooling/oxlint/README.md +25 -0
- package/tooling/oxlint/oxlintrc.json +28 -0
- package/tooling/playwright/playwright.config.d.mts +4 -0
- package/tooling/playwright/playwright.config.mjs +19 -0
- package/tooling/prettier/index.d.mts +4 -0
- package/tooling/prettier/index.mjs +36 -0
- package/tooling/release-please/.release-please-manifest.json +3 -0
- package/tooling/release-please/release-please-config.json +9 -0
- package/tooling/rolldown/rolldown.config.d.mts +18 -0
- package/tooling/rolldown/rolldown.config.mjs +59 -0
- package/tooling/rollup/rollup.config.d.mts +20 -0
- package/tooling/rollup/rollup.config.mjs +70 -0
- package/tooling/semantic-release/docker.d.mts +4 -0
- package/tooling/semantic-release/docker.mjs +59 -0
- package/tooling/semantic-release/github.d.mts +4 -0
- package/tooling/semantic-release/github.mjs +79 -0
- package/tooling/semantic-release/index.d.mts +4 -0
- package/tooling/semantic-release/index.mjs +80 -0
- package/tooling/swift/periphery.yml +4 -0
- package/tooling/swift/swiftlint.yml +23 -0
- package/tooling/tests/exports-resolution.d.mts +14 -0
- package/tooling/tests/exports-resolution.mjs +68 -0
- package/tooling/tests/ssr-safety.d.mts +14 -0
- package/tooling/tests/ssr-safety.mjs +53 -0
- package/tooling/tsup/index.d.mts +8 -0
- package/tooling/tsup/index.mjs +33 -0
- package/tooling/typedoc/typedoc.json +7 -0
- package/tooling/typescript/README.md +49 -0
- package/tooling/typescript/reset.d.ts +9 -0
- package/tooling/typescript/tsconfig.base.json +84 -0
- package/tooling/typescript/tsconfig.build.json +11 -0
- package/tooling/typescript/tsconfig.bun.json +9 -0
- package/tooling/typescript/tsconfig.express.json +9 -0
- package/tooling/typescript/tsconfig.next.json +20 -0
- package/tooling/typescript/tsconfig.node.json +9 -0
- package/tooling/typescript/tsconfig.react.json +15 -0
- package/tooling/typescript/tsconfig.test.json +8 -0
- package/tooling/typescript/v1/tsconfig.base.json +81 -0
- package/tooling/typescript/v1/tsconfig.express.json +9 -0
- package/tooling/typescript/v1/tsconfig.next.json +19 -0
- package/tooling/typescript/v1/tsconfig.node.json +9 -0
- package/tooling/typescript/v1/tsconfig.react.json +14 -0
- package/tooling/typescript/v1/tsconfig.test.json +8 -0
- package/tooling/vite/vite.config.d.mts +4 -0
- package/tooling/vite/vite.config.mjs +18 -0
- package/tooling/vitest/jsdom-shims.d.mts +1 -0
- package/tooling/vitest/jsdom-shims.mjs +58 -0
- package/tooling/vitest/vitest.config.d.mts +4 -0
- package/tooling/vitest/vitest.config.mjs +25 -0
- package/tooling/vitest/vitest.config.react.d.mts +4 -0
- package/tooling/vitest/vitest.config.react.mjs +27 -0
- package/tooling/vitest/vitest.setup.d.mts +1 -0
- package/tooling/vitest/vitest.setup.mjs +3 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
branches: [
|
|
3
|
+
'+([0-9])?(.{+([0-9]),x}).x',
|
|
4
|
+
'main', // โ stable
|
|
5
|
+
'next',
|
|
6
|
+
'release',
|
|
7
|
+
'next-major', // โ next-major branch = next-major tag
|
|
8
|
+
{ name: 'dev', prerelease: true }, // โ dev branch = dev tag
|
|
9
|
+
{ name: 'beta', prerelease: true }, // โ beta branch = beta tag
|
|
10
|
+
{ name: 'alpha', prerelease: true }, // โ alpha branch = alpha tag
|
|
11
|
+
],
|
|
12
|
+
repositoryUrl: `https://github.com/${process.env.GITHUB_REPOSITORY}.git`,
|
|
13
|
+
plugins: [
|
|
14
|
+
[
|
|
15
|
+
'@semantic-release/commit-analyzer',
|
|
16
|
+
{
|
|
17
|
+
preset: 'conventionalcommits',
|
|
18
|
+
releaseRules: [
|
|
19
|
+
{ breaking: true, release: 'major' }, // Major release for breaking changes
|
|
20
|
+
{ type: 'feat', release: 'minor' }, // Minor release for features
|
|
21
|
+
{ type: 'fix', release: 'patch' }, // Patch release for bug fixes
|
|
22
|
+
{
|
|
23
|
+
type: 'docs', // Documentation changes
|
|
24
|
+
scope: 'README', // Specific scope for README changes
|
|
25
|
+
release: false, // no Patch release for README changes
|
|
26
|
+
},
|
|
27
|
+
// { type: 'chore', release: 'patch' }, // Chore changes
|
|
28
|
+
{ type: 'update', release: 'patch' },
|
|
29
|
+
{ type: 'refactor', release: 'patch' },
|
|
30
|
+
{ type: 'revert', release: 'patch' },
|
|
31
|
+
{ type: 'style', release: false },
|
|
32
|
+
{ type: 'test', release: false },
|
|
33
|
+
],
|
|
34
|
+
parserOpts: {
|
|
35
|
+
noteKeywords: ['BREAKING CHANGE', 'BREAKING CHANGES', 'BREAKING'],
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
'@semantic-release/release-notes-generator',
|
|
40
|
+
// Release notes generator plugin to generate release notes
|
|
41
|
+
[
|
|
42
|
+
'@semantic-release/github',
|
|
43
|
+
{
|
|
44
|
+
assets: ['CHANGELOG.md', 'package.json', 'README.md'],
|
|
45
|
+
message: 'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}',
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
[
|
|
49
|
+
'@semantic-release/changelog',
|
|
50
|
+
{
|
|
51
|
+
changelogFile: 'CHANGELOG.md',
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
// npm publishing goes through OIDC trusted publishing โ no NPM_TOKEN. The
|
|
55
|
+
// release job runs with `id-token: write` and npm (>=11.5.1) authenticates
|
|
56
|
+
// via the GitHub Actions trusted publisher configured on the package, and
|
|
57
|
+
// gets provenance for free. Private packages are skipped automatically by
|
|
58
|
+
// @semantic-release/npm; a public repo that only wants GitHub releases can
|
|
59
|
+
// opt out with NPM_PUBLISH=false (the version in package.json is still bumped).
|
|
60
|
+
['@semantic-release/npm', { npmPublish: process.env.NPM_PUBLISH !== 'false', pkgRoot: '.' }],
|
|
61
|
+
[
|
|
62
|
+
'@semantic-release/git',
|
|
63
|
+
{
|
|
64
|
+
assets: ['package.json', 'CHANGELOG.md'],
|
|
65
|
+
message: 'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}',
|
|
66
|
+
// Skip hooks by disabling Husky
|
|
67
|
+
skipCommitHooks: true,
|
|
68
|
+
prepareCmd: 'pnpm exec biome format package.json',
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
],
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// [
|
|
75
|
+
// '@semantic-release/exec',
|
|
76
|
+
// {
|
|
77
|
+
// prepareCmd: 'pnpm exec biome format',
|
|
78
|
+
// },
|
|
79
|
+
// ],
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
branches: [
|
|
3
|
+
'+([0-9])?(.{+([0-9]),x}).x',
|
|
4
|
+
'main', // โ stable
|
|
5
|
+
'next',
|
|
6
|
+
'release',
|
|
7
|
+
'next-major', // โ next-major branch = next-major tag
|
|
8
|
+
{ name: 'dev', prerelease: true }, // โ dev branch = dev tag
|
|
9
|
+
{ name: 'beta', prerelease: true }, // โ beta branch = beta tag
|
|
10
|
+
{ name: 'alpha', prerelease: true }, // โ alpha branch = alpha tag
|
|
11
|
+
],
|
|
12
|
+
repositoryUrl: `https://gitlab-ci-token:${process.env.GITLAB_TOKEN}@gitlab.com/${process.env.CI_PROJECT_NAMESPACE}/${process.env.CI_PROJECT_NAME}.git`,
|
|
13
|
+
plugins: [
|
|
14
|
+
[
|
|
15
|
+
'@semantic-release/commit-analyzer',
|
|
16
|
+
{
|
|
17
|
+
preset: 'conventionalcommits',
|
|
18
|
+
releaseRules: [
|
|
19
|
+
{ breaking: true, release: 'major' }, // Major release for breaking changes
|
|
20
|
+
{ type: 'feat', release: 'minor' }, // Minor release for features
|
|
21
|
+
{ type: 'fix', release: 'patch' }, // Patch release for bug fixes
|
|
22
|
+
{
|
|
23
|
+
type: 'docs', // Documentation changes
|
|
24
|
+
scope: 'README', // Specific scope for README changes
|
|
25
|
+
release: false, // no Patch release for README changes
|
|
26
|
+
},
|
|
27
|
+
// { type: 'chore', release: 'patch' }, // Chore changes
|
|
28
|
+
{ type: 'update', release: 'patch' },
|
|
29
|
+
{ type: 'refactor', release: 'patch' },
|
|
30
|
+
{ type: 'revert', release: 'patch' },
|
|
31
|
+
{ type: 'style', release: false },
|
|
32
|
+
{ type: 'test', release: false },
|
|
33
|
+
],
|
|
34
|
+
parserOpts: {
|
|
35
|
+
noteKeywords: ['BREAKING CHANGE', 'BREAKING CHANGES', 'BREAKING'],
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
'@semantic-release/release-notes-generator',
|
|
40
|
+
// Release notes generator plugin to generate release notes
|
|
41
|
+
[
|
|
42
|
+
'@semantic-release/gitlab',
|
|
43
|
+
{
|
|
44
|
+
assets: ['dist/*.js', 'dist/*.js.map', 'CHANGELOG.md', 'package.json', 'README.md'],
|
|
45
|
+
message: 'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}',
|
|
46
|
+
gitlabUrl: 'https://gitlab.com',
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
[
|
|
50
|
+
'@semantic-release/changelog',
|
|
51
|
+
{
|
|
52
|
+
changelogFile: 'CHANGELOG.md',
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
// npm publishing goes through OIDC trusted publishing โ no NPM_TOKEN. The
|
|
56
|
+
// release job runs with `id-token: write` and npm (>=11.5.1) authenticates
|
|
57
|
+
// via the CI trusted publisher configured on the package, and gets
|
|
58
|
+
// provenance for free. Private packages are skipped automatically by
|
|
59
|
+
// @semantic-release/npm; a repo that only wants VCS releases can opt out
|
|
60
|
+
// with NPM_PUBLISH=false (the version in package.json is still bumped).
|
|
61
|
+
['@semantic-release/npm', { npmPublish: process.env.NPM_PUBLISH !== 'false', pkgRoot: '.' }],
|
|
62
|
+
[
|
|
63
|
+
'@semantic-release/git',
|
|
64
|
+
{
|
|
65
|
+
assets: ['package.json', 'CHANGELOG.md'],
|
|
66
|
+
message: 'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}',
|
|
67
|
+
// Skip hooks by disabling Husky
|
|
68
|
+
skipCommitHooks: true,
|
|
69
|
+
prepareCmd: 'pnpm exec biome format package.json',
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
],
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// [
|
|
76
|
+
// '@semantic-release/exec',
|
|
77
|
+
// {
|
|
78
|
+
// prepareCmd: 'pnpm exec biome format',
|
|
79
|
+
// },
|
|
80
|
+
// ],
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
disabled_rules:
|
|
2
|
+
- weak_delegate
|
|
3
|
+
- cyclomatic_complexity
|
|
4
|
+
- force_unwrapping
|
|
5
|
+
- function_body_length
|
|
6
|
+
- type_name
|
|
7
|
+
- line_length
|
|
8
|
+
- identifier_name
|
|
9
|
+
- trailing_whitespace
|
|
10
|
+
|
|
11
|
+
excluded:
|
|
12
|
+
- .build
|
|
13
|
+
- .swiftpm
|
|
14
|
+
- DerivedData
|
|
15
|
+
|
|
16
|
+
file_length:
|
|
17
|
+
warning: 500
|
|
18
|
+
error: 1200
|
|
19
|
+
|
|
20
|
+
nesting:
|
|
21
|
+
type_level:
|
|
22
|
+
warning: 3
|
|
23
|
+
error: 6
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface ExportsResolutionTestOptions {
|
|
2
|
+
/** Absolute path to the package.json whose `exports` map will be validated. */
|
|
3
|
+
packageJsonPath: string
|
|
4
|
+
/** Absolute path to the source directory whose subfolders are cross-checked. */
|
|
5
|
+
srcDir: string
|
|
6
|
+
/** Folder names under `srcDir` to skip (e.g., `'tests'`, `'common'`). */
|
|
7
|
+
excludeDirs?: string[]
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Asserts that a package.json `exports` map stays in sync with its source folders.
|
|
12
|
+
* Call from a Vitest test file; generates one describe block plus one it per folder.
|
|
13
|
+
*/
|
|
14
|
+
export function runExportsResolutionTest(options: ExportsResolutionTestOptions): void
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { readdirSync, readFileSync } from 'node:fs'
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Asserts that a package.json `exports` map stays in sync with its source folders.
|
|
6
|
+
*
|
|
7
|
+
* For every folder under `srcDir` (excluding `excludeDirs`), the package.json must
|
|
8
|
+
* expose a matching `./<name>` subpath export. Conversely, every subpath in the
|
|
9
|
+
* `exports` map (other than `.`) must point at a folder that exists in `srcDir`.
|
|
10
|
+
*
|
|
11
|
+
* Call this from a Vitest test file; it generates one `describe` block plus one
|
|
12
|
+
* `it` per folder, so failures pinpoint the drift.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* // src/tests/exports-resolution.test.ts
|
|
17
|
+
* import { fileURLToPath } from 'node:url'
|
|
18
|
+
* import { runExportsResolutionTest } from '@rtorcato/repo-tooling/tests/exports-resolution'
|
|
19
|
+
*
|
|
20
|
+
* runExportsResolutionTest({
|
|
21
|
+
* packageJsonPath: fileURLToPath(new URL('../../package.json', import.meta.url)),
|
|
22
|
+
* srcDir: fileURLToPath(new URL('../', import.meta.url)),
|
|
23
|
+
* excludeDirs: ['tests'],
|
|
24
|
+
* })
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @param {object} options
|
|
28
|
+
* @param {string} options.packageJsonPath Absolute path to the package.json under test.
|
|
29
|
+
* @param {string} options.srcDir Absolute path to the source folder whose subdirectories should be cross-checked.
|
|
30
|
+
* @param {string[]} [options.excludeDirs] Folder names under `srcDir` to skip (e.g., `tests`, `common`).
|
|
31
|
+
*/
|
|
32
|
+
export function runExportsResolutionTest({ packageJsonPath, srcDir, excludeDirs = [] }) {
|
|
33
|
+
const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf-8'))
|
|
34
|
+
|
|
35
|
+
if (!pkg.exports || typeof pkg.exports !== 'object') {
|
|
36
|
+
throw new Error(`exports-resolution: package.json at ${packageJsonPath} has no exports map`)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const exportSubpaths = new Set(
|
|
40
|
+
Object.keys(pkg.exports)
|
|
41
|
+
.filter((k) => k !== '.')
|
|
42
|
+
.map((k) => k.replace(/^\.\//, ''))
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
const excluded = new Set(excludeDirs)
|
|
46
|
+
const moduleDirs = readdirSync(srcDir, { withFileTypes: true })
|
|
47
|
+
.filter((d) => d.isDirectory() && !excluded.has(d.name))
|
|
48
|
+
.map((d) => d.name)
|
|
49
|
+
.sort()
|
|
50
|
+
|
|
51
|
+
describe('package.json exports map', () => {
|
|
52
|
+
it('has at least one module', () => {
|
|
53
|
+
expect(moduleDirs.length).toBeGreaterThan(0)
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
for (const dir of moduleDirs) {
|
|
57
|
+
it(`exposes ./${dir}`, () => {
|
|
58
|
+
expect(exportSubpaths.has(dir)).toBe(true)
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
it('has no exports entries pointing at missing src/ folders', () => {
|
|
63
|
+
const moduleDirSet = new Set(moduleDirs)
|
|
64
|
+
const orphans = [...exportSubpaths].filter((k) => !moduleDirSet.has(k))
|
|
65
|
+
expect(orphans).toEqual([])
|
|
66
|
+
})
|
|
67
|
+
})
|
|
68
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface SsrSafetyTestOptions {
|
|
2
|
+
/** Absolute path to the source directory. */
|
|
3
|
+
srcDir: string
|
|
4
|
+
/** Folder names under `srcDir` to skip (e.g., `'tests'`, `'common'`). */
|
|
5
|
+
excludeDirs?: string[]
|
|
6
|
+
/** Entry filename inside each folder. Default: `'index.ts'`. */
|
|
7
|
+
moduleEntry?: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Asserts that every module folder under `srcDir` can be imported in a Node
|
|
12
|
+
* environment without throwing. Call from a Vitest test file.
|
|
13
|
+
*/
|
|
14
|
+
export function runSsrSafetyTest(options: SsrSafetyTestOptions): void
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { readdirSync } from 'node:fs'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
import { pathToFileURL } from 'node:url'
|
|
4
|
+
import { describe, expect, it } from 'vitest'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Asserts that every module folder under `srcDir` can be imported in a Node
|
|
8
|
+
* environment without throwing (no DOM, no `window`, no `document`).
|
|
9
|
+
*
|
|
10
|
+
* For each folder under `srcDir` (excluding `excludeDirs`), the helper resolves
|
|
11
|
+
* `<srcDir>/<name>/<moduleEntry>` and `await import(...)` it. If the import
|
|
12
|
+
* throws or the module accesses a missing global at top level, the test fails.
|
|
13
|
+
*
|
|
14
|
+
* Use this as a contract test for libraries that promise SSR safety โ i.e., that
|
|
15
|
+
* importing a module is always safe even when its underlying API isn't available.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* // src/tests/ssr-safety.test.ts (run with vitest --environment node)
|
|
20
|
+
* import { fileURLToPath } from 'node:url'
|
|
21
|
+
* import { runSsrSafetyTest } from '@rtorcato/repo-tooling/tests/ssr-safety'
|
|
22
|
+
*
|
|
23
|
+
* runSsrSafetyTest({
|
|
24
|
+
* srcDir: fileURLToPath(new URL('../', import.meta.url)),
|
|
25
|
+
* excludeDirs: ['tests'],
|
|
26
|
+
* })
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @param {object} options
|
|
30
|
+
* @param {string} options.srcDir Absolute path to the source folder.
|
|
31
|
+
* @param {string[]} [options.excludeDirs] Folder names under `srcDir` to skip.
|
|
32
|
+
* @param {string} [options.moduleEntry] Entry filename inside each folder. Default: `'index.ts'`.
|
|
33
|
+
*/
|
|
34
|
+
export function runSsrSafetyTest({ srcDir, excludeDirs = [], moduleEntry = 'index.ts' }) {
|
|
35
|
+
const excluded = new Set(excludeDirs)
|
|
36
|
+
const moduleDirs = readdirSync(srcDir, { withFileTypes: true })
|
|
37
|
+
.filter((d) => d.isDirectory() && !excluded.has(d.name))
|
|
38
|
+
.map((d) => d.name)
|
|
39
|
+
.sort()
|
|
40
|
+
|
|
41
|
+
describe('SSR safety', () => {
|
|
42
|
+
it('has at least one module', () => {
|
|
43
|
+
expect(moduleDirs.length).toBeGreaterThan(0)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
for (const dir of moduleDirs) {
|
|
47
|
+
it(`imports ./${dir}/${moduleEntry} without throwing`, async () => {
|
|
48
|
+
const moduleUrl = pathToFileURL(join(srcDir, dir, moduleEntry)).href
|
|
49
|
+
await expect(import(moduleUrl)).resolves.toBeDefined()
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Options } from 'tsup'
|
|
2
|
+
import type { defineConfig } from 'tsup'
|
|
3
|
+
|
|
4
|
+
export type DefineConfig = ReturnType<typeof defineConfig>
|
|
5
|
+
|
|
6
|
+
export declare const getConfig: (customOptions: Options, env: string) => DefineConfig
|
|
7
|
+
|
|
8
|
+
export declare const baseOptions: (options: Options, env: string) => Options
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { defineConfig } from 'tsup'
|
|
2
|
+
|
|
3
|
+
export const getConfig = (customOptions, env) => {
|
|
4
|
+
// tsup invokes this callback with its own CLI options, so `customOptions`
|
|
5
|
+
// must be merged in explicitly โ a `(options = customOptions)` default is
|
|
6
|
+
// bypassed and silently drops the consumer's config (e.g. `entry`). Layer
|
|
7
|
+
// only the DEFINED CLI overrides on top so flags like `--watch` still win
|
|
8
|
+
// without an absent `entry: undefined` clobbering the consumer's entry.
|
|
9
|
+
return defineConfig((cliOptions) => {
|
|
10
|
+
const overrides = Object.fromEntries(
|
|
11
|
+
Object.entries(cliOptions ?? {}).filter(([, value]) => value !== undefined)
|
|
12
|
+
)
|
|
13
|
+
return baseOptions({ ...customOptions, ...overrides }, env)
|
|
14
|
+
})
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const baseOptions = (options, env) => {
|
|
18
|
+
const opts = {
|
|
19
|
+
treeshake: true,
|
|
20
|
+
splitting: true,
|
|
21
|
+
format: ['cjs', 'esm'], // generate cjs and esm files
|
|
22
|
+
// Default to all of src EXCEPT tests, so a consumer that doesn't pass an
|
|
23
|
+
// explicit entry never ships compiled *.test.* / *.spec.* files in dist.
|
|
24
|
+
entry: ['src/**/*.ts', '!src/**/*.test.ts', '!src/**/*.spec.ts'],
|
|
25
|
+
skipNodeModulesBundle: true, // Skips building dependencies for node modules
|
|
26
|
+
minify: !options.watch && env === 'production',
|
|
27
|
+
bundle: false,
|
|
28
|
+
clean: true, // clean up the dist folder
|
|
29
|
+
dts: true, // generate dts file for main module
|
|
30
|
+
...options,
|
|
31
|
+
}
|
|
32
|
+
return opts
|
|
33
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# `tsconfig`
|
|
2
|
+
|
|
3
|
+
These are base shared `tsconfig.json` files from which all other `tsconfig.json`'s inherit.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
1. **Install this package** (if published as a package):
|
|
8
|
+
```sh
|
|
9
|
+
pnpm add -D @your-org/tsconfig
|
|
10
|
+
# or
|
|
11
|
+
npm install --save-dev @your-org/tsconfig
|
|
12
|
+
# or
|
|
13
|
+
yarn add -D @your-org/tsconfig
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
2. **Extend the relevant config in your project `tsconfig.json`:**
|
|
17
|
+
```jsonc
|
|
18
|
+
{
|
|
19
|
+
"extends": "./path/to/tooling/typescript/tsconfig.base.json", // or tsconfig.react.jsonc, etc.
|
|
20
|
+
// ...your overrides
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
Replace the path with the config that matches your project type:
|
|
24
|
+
- `tsconfig.base.jsonc`: General base config
|
|
25
|
+
- `tsconfig.build.jsonc`: For npm package/library builds
|
|
26
|
+
- `tsconfig.react.jsonc`: For React apps
|
|
27
|
+
- `tsconfig.next.jsonc`: For Next.js apps
|
|
28
|
+
- `tsconfig.node.jsonc`: For Node.js/Express APIs
|
|
29
|
+
- `tsconfig.express.jsonc`: (If used) For Express APIs
|
|
30
|
+
|
|
31
|
+
3. **Customizing:**
|
|
32
|
+
You can override or add any settings in your own `tsconfig.json` as needed.
|
|
33
|
+
|
|
34
|
+
## Example
|
|
35
|
+
|
|
36
|
+
```jsonc
|
|
37
|
+
{
|
|
38
|
+
"extends": "../tooling/typescript/tsconfig.react.json",
|
|
39
|
+
// `~/*` and `@/*` โ `./src/*` are inherited from the preset, anchored to this
|
|
40
|
+
// project via ${configDir} โ no `baseUrl`/`paths` needed (baseUrl is deprecated
|
|
41
|
+
// in TS 5.9, removed in TS 7.0).
|
|
42
|
+
"include": ["src"]
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Notes
|
|
47
|
+
- These configs are meant to be shared and extended, not used directly.
|
|
48
|
+
- Pick the config that matches your project type for best results.
|
|
49
|
+
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Do not add any other lines of code to this file!
|
|
2
|
+
import '@total-typescript/ts-reset'
|
|
3
|
+
|
|
4
|
+
// https://www.totaltypescript.com/ts-reset
|
|
5
|
+
// With ts-reset:
|
|
6
|
+
// ๐ .json (in fetch) and JSON.parse both return unknown
|
|
7
|
+
// โ
.filter(Boolean) behaves EXACTLY how you expect
|
|
8
|
+
// ๐ฅน array.includes is widened to be more ergonomic
|
|
9
|
+
// ๐ And several more changes!
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/tsconfig",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
// ๐ง Output & Module Resolution
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"module": "esnext",
|
|
7
|
+
"target": "esnext",
|
|
8
|
+
// "module": "esnext", //
|
|
9
|
+
// "moduleResolution": "node", // Prefer "bundler" if you're using Vite, esbuild, etc.
|
|
10
|
+
// "target": "esnext", //
|
|
11
|
+
"lib": ["ES2022"], // Specify library files to be included in the compilation
|
|
12
|
+
"rootDir": "src",
|
|
13
|
+
"outDir": "dist",
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
// ๐ JavaScript Support
|
|
17
|
+
"allowJs": true, // Allow JavaScript files to be compiled
|
|
18
|
+
"checkJs": true, // Enable type checking on JavaScript files
|
|
19
|
+
"resolveJsonModule": true, // Allow importing JSON files
|
|
20
|
+
"isolatedModules": true, // Ensure that each file can be safely transpiled independently
|
|
21
|
+
"esModuleInterop": true, // Enables emit interoperability between CommonJS and ES Modules
|
|
22
|
+
"allowSyntheticDefaultImports": true, // recommend enabling this for smoother interop
|
|
23
|
+
|
|
24
|
+
// โ๏ธ Module Detection
|
|
25
|
+
"moduleDetection": "force", // Force module detection
|
|
26
|
+
|
|
27
|
+
// ๐ Performance
|
|
28
|
+
"skipLibCheck": true, // Skip type checking of declaration files
|
|
29
|
+
"incremental": true, // Enable incremental compilation
|
|
30
|
+
// Pin the build-info location so downstream emit tools (e.g. tsup's `dts`
|
|
31
|
+
// build) don't hit TS5074 from inheriting `incremental` without a file.
|
|
32
|
+
// ${configDir} resolves to the consuming project's dir (TS 5.5+).
|
|
33
|
+
"tsBuildInfoFile": "${configDir}/node_modules/.cache/tsconfig.tsbuildinfo",
|
|
34
|
+
"disableSourceOfProjectReferenceRedirect": true, // Disable source of project reference redirect
|
|
35
|
+
|
|
36
|
+
// ๐จ Strict Type Checking
|
|
37
|
+
"strict": true, // Enable all strict type checking options
|
|
38
|
+
"noUncheckedIndexedAccess": true, // Disallow accessing an index signature with an arbitrary key
|
|
39
|
+
"noImplicitAny": true, // Disallow implicit any type
|
|
40
|
+
"noImplicitReturns": true, // Disallow functions that do not return a value
|
|
41
|
+
"noImplicitOverride": true, // Ensure override keyword is used
|
|
42
|
+
"noImplicitThis": true, // Disallow 'this' with an implicit any type
|
|
43
|
+
"noPropertyAccessFromIndexSignature": true, // Disallow property access from index signature
|
|
44
|
+
|
|
45
|
+
// ๐งน Lint-Like Settings
|
|
46
|
+
"noUnusedLocals": true, // Disallow unused locals
|
|
47
|
+
"noUnusedParameters": true, // Disallow unused parameters
|
|
48
|
+
"noFallthroughCasesInSwitch": true, // Disallow fallthrough cases in switch statements
|
|
49
|
+
|
|
50
|
+
// ๐ฆ Types & Declarations
|
|
51
|
+
"types": ["node", "vitest"], // Specify type declaration files to be included in the compilation
|
|
52
|
+
"declaration": false, // Do not generate .d.ts files
|
|
53
|
+
"declarationMap": false, // Do not generate sourcemaps for d.ts files
|
|
54
|
+
|
|
55
|
+
// ๐ Emit Settings
|
|
56
|
+
"noEmit": true, // Do not emit output files
|
|
57
|
+
"sourceMap": true, // Generate sourcemaps for .ts files
|
|
58
|
+
|
|
59
|
+
// ${configDir} anchors paths to the consuming project (TS 5.5+), so
|
|
60
|
+
// downstream repos no longer need `baseUrl` + a redeclared `paths` block
|
|
61
|
+
// (baseUrl is deprecated in TS 5.9, removed in TS 7.0). Refs: https://aka.ms/ts6
|
|
62
|
+
"paths": { // Path mapping for module resolution
|
|
63
|
+
"~/*": ["${configDir}/src/*"],
|
|
64
|
+
"@/*": ["${configDir}/src/*"]
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"include": ["src/**/*", "index.d.ts"], // Include files in the src directory and index.d.ts
|
|
68
|
+
"exclude": [
|
|
69
|
+
"node_modules",
|
|
70
|
+
"build",
|
|
71
|
+
"dist",
|
|
72
|
+
".next",
|
|
73
|
+
".expo",
|
|
74
|
+
"OLD",
|
|
75
|
+
"**/*.test.ts",
|
|
76
|
+
"**/*.test.tsx",
|
|
77
|
+
"**/*.spec.ts",
|
|
78
|
+
"**/*.spec.tsx",
|
|
79
|
+
".turbo",
|
|
80
|
+
"out",
|
|
81
|
+
"not-used",
|
|
82
|
+
"vitest.config.ts"
|
|
83
|
+
] // Exclude directories from compilation
|
|
84
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"noEmit": false, // Emit output files
|
|
5
|
+
"emitDeclarationOnly": true, // Emit JS and .d.ts files
|
|
6
|
+
"declaration": true, // Generate .d.ts files
|
|
7
|
+
"declarationMap": true, // (optional) Generate sourcemaps for d.ts files
|
|
8
|
+
"outDir": "dist" // Output directory for build
|
|
9
|
+
},
|
|
10
|
+
"exclude": ["dist", "node_modules", "**/*.test.ts", "**/*.test.tsx", "**/*.spec.ts", "**/*.spec.tsx"]
|
|
11
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"lib": ["ES2022"], // Only include ES libs, no DOM
|
|
5
|
+
"types": ["node", "express", "vitest"], // Add express types for API development
|
|
6
|
+
},
|
|
7
|
+
"include": ["src", "index.d.ts"],
|
|
8
|
+
"exclude": ["node_modules", "dist", "build", "test", "**/*.test.ts", "**/*.spec.ts"]
|
|
9
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"jsx": "preserve", // Let Next.js handle JSX transformation
|
|
5
|
+
"lib": ["DOM", "DOM.Iterable", "ESNext"], // Include DOM types for browser APIs
|
|
6
|
+
"module": "esnext", // Next.js expects ESNext modules
|
|
7
|
+
"moduleResolution": "bundler", // Modern module resolution for Next.js
|
|
8
|
+
"allowJs": true, // Allow JavaScript files
|
|
9
|
+
"esModuleInterop": true, // Interop for CommonJS/ESM
|
|
10
|
+
"types": ["react", "tailwindcss", "vitest"],
|
|
11
|
+
"plugins": [ { "name": "next" } ], // Next.js plugin for TypeScript
|
|
12
|
+
// ${configDir} anchors paths to the consuming project (drops deprecated baseUrl)
|
|
13
|
+
"paths": {
|
|
14
|
+
"~/*": ["${configDir}/src/*"],
|
|
15
|
+
"@/*": ["${configDir}/src/*"]
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"include": ["next-env.d.ts", "src", "pages", "app", "components", "types", "index.d.ts"],
|
|
19
|
+
"exclude": ["node_modules", "dist", ".next", "build", "out"]
|
|
20
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"jsx": "react-jsx", // Use the new JSX transform for React 17+
|
|
5
|
+
"lib": ["DOM", "DOM.Iterable", "ESNext"],// Include DOM types for browser APIs
|
|
6
|
+
"types": ["react", "react-dom", "tailwindcss", "vitest"],
|
|
7
|
+
// ${configDir} anchors paths to the consuming project (drops deprecated baseUrl)
|
|
8
|
+
"paths": {
|
|
9
|
+
"~/*": ["${configDir}/src/*"],
|
|
10
|
+
"@/*": ["${configDir}/src/*"]
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"include": ["src", "index.d.ts", "types"],
|
|
14
|
+
"exclude": ["node_modules", "dist", "build", "out", "**/*.test.ts", "**/*.spec.ts"]
|
|
15
|
+
}
|