@rtorcato/js-tooling 2.5.1 → 2.7.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.
@@ -0,0 +1,193 @@
1
+ export const PRESET_NAMES = [
2
+ 'library',
3
+ 'web-app',
4
+ 'node-api',
5
+ 'nextjs-app',
6
+ 'react-app',
7
+ ];
8
+ const BASE = {
9
+ linting: { tool: 'biome' },
10
+ formatting: { tool: 'biome' },
11
+ testing: { framework: 'vitest', environment: 'node' },
12
+ gitHooks: true,
13
+ commitLint: true,
14
+ semanticRelease: false,
15
+ securityAutomation: true,
16
+ };
17
+ export function buildPresetConfig(name, projectName) {
18
+ switch (name) {
19
+ case 'library':
20
+ return {
21
+ ...BASE,
22
+ projectName,
23
+ projectType: 'library',
24
+ typescript: { enabled: true, config: 'base' },
25
+ semanticRelease: true,
26
+ bundler: 'tsup',
27
+ };
28
+ case 'web-app':
29
+ return {
30
+ ...BASE,
31
+ projectName,
32
+ projectType: 'web-app',
33
+ typescript: { enabled: true, config: 'base' },
34
+ testing: { framework: 'vitest', environment: 'browser' },
35
+ bundler: 'vite',
36
+ };
37
+ case 'node-api':
38
+ return {
39
+ ...BASE,
40
+ projectName,
41
+ projectType: 'node-api',
42
+ typescript: { enabled: true, config: 'node' },
43
+ bundler: 'esbuild',
44
+ };
45
+ case 'nextjs-app':
46
+ return {
47
+ ...BASE,
48
+ projectName,
49
+ projectType: 'nextjs-app',
50
+ typescript: { enabled: true, config: 'next' },
51
+ linting: { tool: 'eslint', eslintConfig: 'nextjs' },
52
+ formatting: { tool: 'prettier' },
53
+ bundler: 'none',
54
+ };
55
+ case 'react-app':
56
+ return {
57
+ ...BASE,
58
+ projectName,
59
+ projectType: 'react-app',
60
+ typescript: { enabled: true, config: 'react' },
61
+ testing: { framework: 'vitest', environment: 'browser' },
62
+ bundler: 'vite',
63
+ };
64
+ }
65
+ }
66
+ export const CONFIG_SCHEMA = {
67
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
68
+ $id: 'https://rtorcato.github.io/js-tooling/schemas/project-config.json',
69
+ title: 'ProjectConfig',
70
+ description: '@rtorcato/js-tooling setup configuration',
71
+ type: 'object',
72
+ additionalProperties: false,
73
+ required: [
74
+ 'projectName',
75
+ 'projectType',
76
+ 'typescript',
77
+ 'linting',
78
+ 'formatting',
79
+ 'testing',
80
+ 'gitHooks',
81
+ 'commitLint',
82
+ 'semanticRelease',
83
+ 'securityAutomation',
84
+ 'bundler',
85
+ ],
86
+ properties: {
87
+ projectName: { type: 'string', minLength: 1 },
88
+ projectType: {
89
+ type: 'string',
90
+ enum: ['library', 'web-app', 'node-api', 'nextjs-app', 'react-app'],
91
+ },
92
+ typescript: {
93
+ type: 'object',
94
+ additionalProperties: false,
95
+ required: ['enabled', 'config'],
96
+ properties: {
97
+ enabled: { type: 'boolean' },
98
+ config: { type: 'string', enum: ['base', 'react', 'next', 'node', 'express'] },
99
+ },
100
+ },
101
+ linting: {
102
+ type: 'object',
103
+ additionalProperties: false,
104
+ required: ['tool'],
105
+ properties: {
106
+ tool: { type: 'string', enum: ['biome', 'eslint', 'both', 'none'] },
107
+ eslintConfig: { type: 'string', enum: ['base', 'nextjs'] },
108
+ },
109
+ },
110
+ formatting: {
111
+ type: 'object',
112
+ additionalProperties: false,
113
+ required: ['tool'],
114
+ properties: { tool: { type: 'string', enum: ['biome', 'prettier', 'none'] } },
115
+ },
116
+ testing: {
117
+ type: 'object',
118
+ additionalProperties: false,
119
+ required: ['framework'],
120
+ properties: {
121
+ framework: { type: 'string', enum: ['vitest', 'jest', 'playwright', 'none'] },
122
+ environment: { type: 'string', enum: ['node', 'browser', 'both'] },
123
+ },
124
+ },
125
+ gitHooks: { type: 'boolean' },
126
+ commitLint: { type: 'boolean' },
127
+ semanticRelease: { type: 'boolean' },
128
+ securityAutomation: { type: 'boolean' },
129
+ bundler: { type: 'string', enum: ['tsup', 'esbuild', 'vite', 'none'] },
130
+ },
131
+ };
132
+ const ALLOWED_KEYS = new Set(CONFIG_SCHEMA.required);
133
+ export function validateProjectConfig(input) {
134
+ const errors = [];
135
+ if (typeof input !== 'object' || input === null || Array.isArray(input)) {
136
+ return { valid: false, errors: ['Config must be a JSON object'] };
137
+ }
138
+ const obj = input;
139
+ for (const key of Object.keys(obj)) {
140
+ if (!ALLOWED_KEYS.has(key))
141
+ errors.push(`Unknown field: ${key}`);
142
+ }
143
+ for (const required of CONFIG_SCHEMA.required) {
144
+ if (!(required in obj))
145
+ errors.push(`Missing required field: ${required}`);
146
+ }
147
+ return { valid: errors.length === 0, errors };
148
+ }
149
+ export function computeFileList(config) {
150
+ const files = ['package.json'];
151
+ files.push('.editorconfig', '.nvmrc', 'knip.json');
152
+ if (config.typescript.enabled) {
153
+ files.push('tsconfig.json', 'reset.d.ts');
154
+ }
155
+ if (config.linting.tool === 'biome' || config.linting.tool === 'both') {
156
+ files.push('biome.jsonc');
157
+ }
158
+ if (config.linting.tool === 'eslint' || config.linting.tool === 'both') {
159
+ files.push('eslint.config.mjs');
160
+ }
161
+ if (config.linting.tool === 'eslint') {
162
+ files.push('prettier.config.mjs');
163
+ }
164
+ if (config.testing.framework === 'vitest') {
165
+ files.push('vitest.config.ts', 'vitest.setup.ts');
166
+ }
167
+ if (config.testing.framework === 'jest') {
168
+ files.push('jest.config.mjs');
169
+ }
170
+ if (config.testing.framework === 'playwright') {
171
+ files.push('playwright.config.ts');
172
+ }
173
+ if (config.gitHooks) {
174
+ files.push('.husky/pre-commit', '.gitignore');
175
+ }
176
+ if (config.commitLint) {
177
+ files.push('.husky/commit-msg', 'commitlint.config.mjs');
178
+ }
179
+ files.push('.github/workflows/ci.yml');
180
+ if (config.securityAutomation) {
181
+ files.push('.github/dependabot.yml', '.github/workflows/codeql.yml');
182
+ }
183
+ if (config.bundler === 'tsup')
184
+ files.push('tsup.config.ts');
185
+ else if (config.bundler === 'esbuild')
186
+ files.push('build.mjs');
187
+ else if (config.bundler === 'vite')
188
+ files.push('vite.config.ts');
189
+ if (config.semanticRelease)
190
+ files.push('release.config.mjs');
191
+ files.push('README.md');
192
+ return files;
193
+ }
@@ -1,17 +1,58 @@
1
+ import path from 'node:path';
1
2
  import chalk from 'chalk';
2
3
  import fs from 'fs-extra';
3
4
  import inquirer from 'inquirer';
4
- import path from 'node:path';
5
5
  import { generateConfigs } from '../generators/index.js';
6
6
  import { installDependencies } from '../utils/install.js';
7
+ import { buildPresetConfig, computeFileList, CONFIG_SCHEMA, PRESET_NAMES, validateProjectConfig, } from './setup-presets.js';
8
+ async function resolveConfig(options) {
9
+ if (options.config && options.preset) {
10
+ console.warn(chalk.yellow('⚠️ Both --config and --preset given; --config wins.\n'));
11
+ }
12
+ if (options.config) {
13
+ const configPath = path.resolve(options.config);
14
+ if (!(await fs.pathExists(configPath))) {
15
+ throw new Error(`Config file not found: ${configPath}`);
16
+ }
17
+ const raw = await fs.readJson(configPath);
18
+ const { valid, errors } = validateProjectConfig(raw);
19
+ if (!valid) {
20
+ throw new Error(`Invalid config:\n - ${errors.join('\n - ')}`);
21
+ }
22
+ return raw;
23
+ }
24
+ if (options.preset) {
25
+ if (!PRESET_NAMES.includes(options.preset)) {
26
+ throw new Error(`Unknown preset: ${options.preset}. Available: ${PRESET_NAMES.join(', ')}`);
27
+ }
28
+ const projectName = path.basename(path.resolve(options.directory));
29
+ return buildPresetConfig(options.preset, projectName);
30
+ }
31
+ return promptForConfig();
32
+ }
7
33
  export async function setupProject(options) {
34
+ if (options.configSchema) {
35
+ console.log(JSON.stringify(CONFIG_SCHEMA, null, 2));
36
+ return;
37
+ }
8
38
  const targetDir = path.resolve(options.directory);
9
- console.log(chalk.cyan('\n🛠️ Welcome to JS Tooling Setup!\n'));
10
- console.log(chalk.gray(`Setting up tooling in: ${targetDir}\n`));
39
+ const interactive = !options.config && !options.preset;
40
+ const dryRun = options.dryRun === true;
41
+ if (interactive && !dryRun) {
42
+ console.log(chalk.cyan('\n🛠️ Welcome to JS Tooling Setup!\n'));
43
+ console.log(chalk.gray(`Setting up tooling in: ${targetDir}\n`));
44
+ }
11
45
  try {
12
- // Check if directory exists and is writable
13
46
  await fs.ensureDir(targetDir);
14
- const config = await promptForConfig();
47
+ const config = await resolveConfig(options);
48
+ if (dryRun) {
49
+ const files = computeFileList(config);
50
+ console.log(JSON.stringify({ directory: targetDir, config, files }, null, 2));
51
+ return;
52
+ }
53
+ if (!interactive) {
54
+ console.log(chalk.cyan(`\n🛠️ Scaffolding ${config.projectType} in ${targetDir}\n`));
55
+ }
15
56
  console.log(chalk.cyan('\n📝 Generating configuration files...\n'));
16
57
  await generateConfigs(config, targetDir);
17
58
  if (!options.skipInstall) {
@@ -19,7 +60,6 @@ export async function setupProject(options) {
19
60
  await installDependencies(config, targetDir);
20
61
  }
21
62
  console.log(chalk.green('\n✅ Setup completed successfully!\n'));
22
- // Show next steps
23
63
  showNextSteps(config, targetDir);
24
64
  }
25
65
  catch (error) {
package/dist/cli/index.js CHANGED
@@ -28,6 +28,10 @@ program
28
28
  .description('🚀 Setup tooling for a new or existing project')
29
29
  .option('-d, --directory <path>', 'Target directory for setup', process.cwd())
30
30
  .option('--skip-install', 'Skip installing dependencies')
31
+ .option('--preset <name>', 'Skip prompts; use defaults for a project type')
32
+ .option('--config <path>', 'Skip prompts; read a JSON ProjectConfig from <path>')
33
+ .option('--dry-run', 'Print the resolved config and file list, write nothing')
34
+ .option('--config-schema', 'Print the JSON Schema for ProjectConfig and exit')
31
35
  .action(setupProject);
32
36
  program
33
37
  .command('copy <config>')
@@ -52,41 +56,155 @@ program
52
56
  console.error(chalk.red(`\n❌ Error copying configuration: ${error}\n`));
53
57
  }
54
58
  });
59
+ const TOOL_CATALOG = [
60
+ {
61
+ name: 'TypeScript',
62
+ description: 'Base, React, Next.js, Node.js, Express tsconfig presets',
63
+ exports: [
64
+ '@rtorcato/js-tooling/typescript/base',
65
+ '@rtorcato/js-tooling/typescript/react',
66
+ '@rtorcato/js-tooling/typescript/next',
67
+ '@rtorcato/js-tooling/typescript/node',
68
+ '@rtorcato/js-tooling/typescript/express',
69
+ '@rtorcato/js-tooling/typescript/test',
70
+ '@rtorcato/js-tooling/typescript/reset',
71
+ ],
72
+ fixTarget: 'tsconfig',
73
+ },
74
+ {
75
+ name: 'ESLint',
76
+ description: 'Base and Next.js ESLint configurations',
77
+ exports: ['@rtorcato/js-tooling/eslint/base', '@rtorcato/js-tooling/eslint/nextjs'],
78
+ fixTarget: 'eslint',
79
+ },
80
+ {
81
+ name: 'Biome',
82
+ description: 'Fast formatter and linter configuration',
83
+ exports: ['@rtorcato/js-tooling/biome'],
84
+ fixTarget: 'biome',
85
+ },
86
+ {
87
+ name: 'Prettier',
88
+ description: 'Code formatter configuration',
89
+ exports: ['@rtorcato/js-tooling/prettier'],
90
+ fixTarget: 'prettier',
91
+ },
92
+ {
93
+ name: 'Vitest',
94
+ description: 'Testing framework configuration',
95
+ exports: [
96
+ '@rtorcato/js-tooling/vitest/config',
97
+ '@rtorcato/js-tooling/vitest/react',
98
+ '@rtorcato/js-tooling/vitest/setup',
99
+ ],
100
+ fixTarget: 'vitest',
101
+ },
102
+ {
103
+ name: 'Jest',
104
+ description: 'Testing framework presets for browser and Node.js',
105
+ exports: [
106
+ '@rtorcato/js-tooling/jest-presets/browser/jest-preset',
107
+ '@rtorcato/js-tooling/jest-presets/node/jest-preset',
108
+ ],
109
+ fixTarget: null,
110
+ },
111
+ {
112
+ name: 'Playwright',
113
+ description: 'End-to-end testing configuration',
114
+ exports: ['@rtorcato/js-tooling/playwright'],
115
+ fixTarget: null,
116
+ },
117
+ {
118
+ name: 'Commitlint',
119
+ description: 'Conventional commit linting',
120
+ exports: ['@rtorcato/js-tooling/commitlint/config'],
121
+ fixTarget: 'commitlint',
122
+ },
123
+ {
124
+ name: 'Husky',
125
+ description: 'Git hooks for pre-commit validation',
126
+ exports: [],
127
+ fixTarget: 'husky',
128
+ },
129
+ {
130
+ name: 'lint-staged',
131
+ description: 'Run linters on staged files (pairs with Husky)',
132
+ exports: [],
133
+ fixTarget: 'husky',
134
+ },
135
+ {
136
+ name: 'Semantic Release',
137
+ description: 'Automated versioning and publishing',
138
+ exports: [
139
+ '@rtorcato/js-tooling/semantic-release',
140
+ '@rtorcato/js-tooling/semantic-release/github',
141
+ '@rtorcato/js-tooling/semantic-release/docker',
142
+ ],
143
+ fixTarget: 'semantic-release',
144
+ },
145
+ {
146
+ name: 'tsup',
147
+ description: 'TypeScript bundler configuration',
148
+ exports: ['@rtorcato/js-tooling/tsup'],
149
+ fixTarget: null,
150
+ },
151
+ {
152
+ name: 'esbuild',
153
+ description: 'Fast JavaScript bundler configuration',
154
+ exports: ['@rtorcato/js-tooling/esbuild'],
155
+ fixTarget: null,
156
+ },
157
+ {
158
+ name: 'Vite',
159
+ description: 'Modern web app build tool configuration',
160
+ exports: ['@rtorcato/js-tooling/vite'],
161
+ fixTarget: null,
162
+ },
163
+ {
164
+ name: 'EditorConfig',
165
+ description: 'Cross-editor formatting consistency (.editorconfig)',
166
+ exports: [],
167
+ fixTarget: 'editorconfig',
168
+ },
169
+ {
170
+ name: '.nvmrc',
171
+ description: 'Pin Node version per repository',
172
+ exports: [],
173
+ fixTarget: 'nvmrc',
174
+ },
175
+ {
176
+ name: 'knip',
177
+ description: 'Find unused files, exports, and dependencies',
178
+ exports: [],
179
+ fixTarget: 'knip',
180
+ },
181
+ {
182
+ name: 'Dependabot',
183
+ description: 'Weekly automated dependency updates',
184
+ exports: [],
185
+ fixTarget: 'dependabot',
186
+ },
187
+ {
188
+ name: 'CodeQL',
189
+ description: 'GitHub security scanning workflow',
190
+ exports: [],
191
+ fixTarget: 'codeql',
192
+ },
193
+ ];
55
194
  program
56
195
  .command('list')
57
196
  .alias('ls')
58
197
  .description('📋 List all available tooling configurations')
59
- .action(() => {
198
+ .option('--json', 'Emit machine-readable JSON output')
199
+ .action((options) => {
200
+ if (options.json) {
201
+ console.log(JSON.stringify({ tools: TOOL_CATALOG }, null, 2));
202
+ return;
203
+ }
60
204
  console.log(chalk.cyan('\n🛠️ Available tooling configurations:\n'));
61
- const configs = [
62
- {
63
- name: 'TypeScript',
64
- desc: 'Base, React, Next.js, Node.js, Express configurations',
65
- },
66
- { name: 'ESLint', desc: 'Base and Next.js ESLint configurations' },
67
- { name: 'Biome', desc: 'Fast formatter and linter configuration' },
68
- { name: 'Prettier', desc: 'Code formatter configuration' },
69
- { name: 'Vitest', desc: 'Testing framework configuration' },
70
- {
71
- name: 'Jest',
72
- desc: 'Testing framework presets for browser and Node.js',
73
- },
74
- { name: 'Playwright', desc: 'End-to-end testing configuration' },
75
- { name: 'Commitlint', desc: 'Conventional commit linting' },
76
- { name: 'Husky', desc: 'Git hooks for pre-commit validation' },
77
- { name: 'lint-staged', desc: 'Run linters on staged files (pairs with Husky)' },
78
- { name: 'Semantic Release', desc: 'Automated versioning and publishing' },
79
- { name: 'tsup', desc: 'TypeScript bundler configuration' },
80
- { name: 'esbuild', desc: 'Fast JavaScript bundler configuration' },
81
- { name: 'EditorConfig', desc: 'Cross-editor formatting consistency (.editorconfig)' },
82
- { name: '.nvmrc', desc: 'Pin Node version per repository' },
83
- { name: 'knip', desc: 'Find unused files, exports, and dependencies' },
84
- { name: 'Dependabot', desc: 'Weekly automated dependency updates' },
85
- { name: 'CodeQL', desc: 'GitHub security scanning workflow' },
86
- ];
87
- configs.forEach(({ name, desc }) => {
88
- console.log(` ${chalk.green('●')} ${chalk.bold(name)}: ${chalk.gray(desc)}`);
89
- });
205
+ for (const { name, description } of TOOL_CATALOG) {
206
+ console.log(` ${chalk.green('●')} ${chalk.bold(name)}: ${chalk.gray(description)}`);
207
+ }
90
208
  console.log(chalk.dim('\n💡 Run `js-tooling setup` for a new project'));
91
209
  console.log(chalk.dim(' or `js-tooling fix` to apply missing pieces to an existing one\n'));
92
210
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rtorcato/js-tooling",
3
- "version": "2.5.1",
3
+ "version": "2.7.0",
4
4
  "description": "JavaScript and TypeScript tooling for Node.js, React, Next.js, and Vitest.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -61,6 +61,8 @@
61
61
  "tooling/vitest/vitest.config.react.d.mts",
62
62
  "tooling/vitest/vitest.setup.mjs",
63
63
  "tooling/vitest/vitest.setup.d.mts",
64
+ "tooling/vitest/jsdom-shims.mjs",
65
+ "tooling/vitest/jsdom-shims.d.mts",
64
66
  "tooling/tsup/index.ts",
65
67
  "tooling/biome/biome.json",
66
68
  "tooling/semantic-release/*.mjs",
@@ -123,6 +125,10 @@
123
125
  "types": "./tooling/vitest/vitest.setup.d.mts",
124
126
  "import": "./tooling/vitest/vitest.setup.mjs"
125
127
  },
128
+ "./vitest/jsdom-shims": {
129
+ "types": "./tooling/vitest/jsdom-shims.d.mts",
130
+ "import": "./tooling/vitest/jsdom-shims.mjs"
131
+ },
126
132
  "./tsup": "./tooling/tsup/index.ts",
127
133
  "./biome": "./tooling/biome/biome.json",
128
134
  "./semantic-release": {
@@ -146,20 +152,20 @@
146
152
  },
147
153
  "devDependencies": {
148
154
  "@biomejs/biome": "^2.3.0",
155
+ "@commitlint/cli": "^20.1.0",
156
+ "@commitlint/config-conventional": "^21.0.1",
149
157
  "@commitlint/types": "^20.0.0",
150
158
  "@eslint/js": "^9.38.0",
151
159
  "@ianvs/prettier-plugin-sort-imports": "^4.4.2",
152
- "@commitlint/cli": "^20.1.0",
153
- "@commitlint/config-conventional": "^21.0.1",
154
160
  "@next/eslint-plugin-next": "^16.0.0",
155
161
  "@playwright/test": "^1.56.1",
156
162
  "@semantic-release/changelog": "^6.0.3",
157
163
  "@semantic-release/commit-analyzer": "^13.0.1",
158
164
  "@semantic-release/exec": "^7.1.0",
159
165
  "@semantic-release/git": "^10.0.1",
160
- "@semantic-release/github": "^12.0.0",
161
- "@semantic-release/npm": "^13.1.1",
162
- "@semantic-release/release-notes-generator": "^14.1.0",
166
+ "@semantic-release/github": "^12.0.8",
167
+ "@semantic-release/npm": "^13.1.5",
168
+ "@semantic-release/release-notes-generator": "^14.1.1",
163
169
  "@total-typescript/ts-reset": "0.6.1",
164
170
  "@types/fs-extra": "^11.0.4",
165
171
  "@types/node": "^25.9.1",
@@ -175,19 +181,20 @@
175
181
  "eslint": "9.38.0",
176
182
  "eslint-plugin-import": "^2.32.0",
177
183
  "eslint-plugin-jest": "29.0.1",
178
- "jest": "^29.7.0",
179
184
  "husky": "^9.1.7",
180
185
  "is-ci": "^4.1.0",
186
+ "jest": "^29.7.0",
187
+ "jsdom": "^26.1.0",
188
+ "knip": "^5.61.3",
181
189
  "lint-staged": "^16.2.6",
182
190
  "prettier": "^3.6.2",
183
191
  "rimraf": "6.0.1",
184
- "semantic-release": "^25.0.1",
192
+ "semantic-release": "^25.0.3",
185
193
  "ts-jest": "^29.4.5",
186
194
  "tsup": "8.5.1",
187
195
  "typescript": "^5.9.3",
188
196
  "typescript-eslint": "^8.60.0",
189
- "vitest": "4.0.3",
190
- "knip": "^5.61.3"
197
+ "vitest": "4.0.3"
191
198
  },
192
199
  "peerDependencies": {
193
200
  "@biomejs/biome": "^2.0.0",
@@ -201,7 +208,7 @@
201
208
  "@semantic-release/commit-analyzer": "^13.0.0",
202
209
  "@semantic-release/exec": "^7.0.0",
203
210
  "@semantic-release/git": "^10.0.0",
204
- "@semantic-release/github": "^12.0.0",
211
+ "@semantic-release/github": "^12.0.8",
205
212
  "@semantic-release/npm": "^13.0.0",
206
213
  "@semantic-release/release-notes-generator": "^14.0.0",
207
214
  "@total-typescript/ts-reset": "^0.6.0",
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,58 @@
1
+ // jsdom doesn't ship the browser APIs that Radix UI, cmdk, embla-carousel,
2
+ // react-day-picker and friends call at mount time. Import this file from your
3
+ // vitest setupFiles to install no-op polyfills for all of them:
4
+ //
5
+ // // vitest.config.ts -> test.setupFiles
6
+ // import '@rtorcato/js-tooling/vitest/jsdom-shims'
7
+ //
8
+ // Side-effect only; nothing is exported.
9
+
10
+ if (typeof Element !== 'undefined') {
11
+ if (!Element.prototype.hasPointerCapture) {
12
+ Element.prototype.hasPointerCapture = () => false
13
+ }
14
+ if (!Element.prototype.setPointerCapture) {
15
+ Element.prototype.setPointerCapture = () => {}
16
+ }
17
+ if (!Element.prototype.releasePointerCapture) {
18
+ Element.prototype.releasePointerCapture = () => {}
19
+ }
20
+ if (!Element.prototype.scrollIntoView) {
21
+ Element.prototype.scrollIntoView = () => {}
22
+ }
23
+ }
24
+
25
+ if (typeof globalThis.ResizeObserver === 'undefined') {
26
+ globalThis.ResizeObserver = class ResizeObserver {
27
+ observe() {}
28
+ unobserve() {}
29
+ disconnect() {}
30
+ }
31
+ }
32
+
33
+ if (typeof globalThis.IntersectionObserver === 'undefined') {
34
+ globalThis.IntersectionObserver = class IntersectionObserver {
35
+ observe() {}
36
+ unobserve() {}
37
+ disconnect() {}
38
+ takeRecords() {
39
+ return []
40
+ }
41
+ root = null
42
+ rootMargin = ''
43
+ thresholds = []
44
+ }
45
+ }
46
+
47
+ if (typeof window !== 'undefined' && typeof window.matchMedia === 'undefined') {
48
+ window.matchMedia = (query) => ({
49
+ matches: false,
50
+ media: query,
51
+ onchange: null,
52
+ addListener: () => {},
53
+ removeListener: () => {},
54
+ addEventListener: () => {},
55
+ removeEventListener: () => {},
56
+ dispatchEvent: () => false,
57
+ })
58
+ }