@santi020k/eslint-config-basic 2.0.0-beta.0 → 2.0.0-beta.3

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/CHANGELOG.md CHANGED
@@ -1,5 +1,101 @@
1
1
  # @santi020k/eslint-config-basic
2
2
 
3
+ ## 2.0.0-beta.3
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [[`af152cd`](https://github.com/santi020k/eslint-config-basic/commit/af152cda17961f9de8ca7bf069739f151fca65be)]:
8
+ - @santi020k/eslint-config-core@2.0.0-beta.3
9
+ - @santi020k/eslint-config-integrations@2.0.0-beta.3
10
+ - @santi020k/eslint-config-typescript@2.0.0-beta.3
11
+ - @santi020k/eslint-config-angular@2.0.0-beta.3
12
+ - @santi020k/eslint-config-astro@2.0.0-beta.3
13
+ - @santi020k/eslint-config-expo@2.0.0-beta.3
14
+ - @santi020k/eslint-config-hono@2.0.0-beta.3
15
+ - @santi020k/eslint-config-lit@2.0.0-beta.3
16
+ - @santi020k/eslint-config-nest@2.0.0-beta.3
17
+ - @santi020k/eslint-config-next@2.0.0-beta.3
18
+ - @santi020k/eslint-config-nuxt@2.0.0-beta.3
19
+ - @santi020k/eslint-config-qwik@2.0.0-beta.3
20
+ - @santi020k/eslint-config-react@2.0.0-beta.3
21
+ - @santi020k/eslint-config-react-router@2.0.0-beta.3
22
+ - @santi020k/eslint-config-remix@2.0.0-beta.3
23
+ - @santi020k/eslint-config-slidev@2.0.0-beta.3
24
+ - @santi020k/eslint-config-solid@2.0.0-beta.3
25
+ - @santi020k/eslint-config-svelte@2.0.0-beta.3
26
+ - @santi020k/eslint-config-tanstack-start@2.0.0-beta.3
27
+ - @santi020k/eslint-config-vite@2.0.0-beta.3
28
+ - @santi020k/eslint-config-vue@2.0.0-beta.3
29
+ - @santi020k/eslint-config-preact@2.0.0-beta.3
30
+
31
+ ## 2.0.0-beta.2
32
+
33
+ ### Minor Changes
34
+
35
+ - Tailwind `noUnknownClasses` option, expanded testing config names, and virtual TS parser fix.
36
+
37
+ - **`TailwindOptions.noUnknownClasses`**: new optional field (`'error' | 'warn' | 'off' | false`) to control the `better-tailwindcss/no-unknown-classes` rule severity. Defaults to `'error'` when a Tailwind entry point is detected; set to `false` or `'off'` to disable.
38
+ - **Testing config overrides**: `TESTING_CONFIG_NAMES` now maps Cypress, Jest, JestDom, Playwright, TestingLibrary, and Vitest — so per-testing-tool file overrides are applied for all supported testing integrations, not just Playwright.
39
+ - **TypeScript virtual file parser**: the parser-setup config block now also covers virtual TS files (`parserSetupFiles` includes `GLOB_VIRTUAL_TS`), fixing missing parser options for framework-generated virtual modules.
40
+
41
+ ### Patch Changes
42
+
43
+ - Updated dependencies []:
44
+ - @santi020k/eslint-config-core@2.0.0-beta.2
45
+ - @santi020k/eslint-config-typescript@2.0.0-beta.2
46
+ - @santi020k/eslint-config-integrations@2.0.0-beta.2
47
+ - @santi020k/eslint-config-angular@2.0.0-beta.2
48
+ - @santi020k/eslint-config-astro@2.0.0-beta.2
49
+ - @santi020k/eslint-config-expo@2.0.0-beta.2
50
+ - @santi020k/eslint-config-hono@2.0.0-beta.2
51
+ - @santi020k/eslint-config-lit@2.0.0-beta.2
52
+ - @santi020k/eslint-config-nest@2.0.0-beta.2
53
+ - @santi020k/eslint-config-next@2.0.0-beta.2
54
+ - @santi020k/eslint-config-nuxt@2.0.0-beta.2
55
+ - @santi020k/eslint-config-qwik@2.0.0-beta.2
56
+ - @santi020k/eslint-config-react@2.0.0-beta.2
57
+ - @santi020k/eslint-config-react-router@2.0.0-beta.2
58
+ - @santi020k/eslint-config-remix@2.0.0-beta.2
59
+ - @santi020k/eslint-config-slidev@2.0.0-beta.2
60
+ - @santi020k/eslint-config-solid@2.0.0-beta.2
61
+ - @santi020k/eslint-config-svelte@2.0.0-beta.2
62
+ - @santi020k/eslint-config-tanstack-start@2.0.0-beta.2
63
+ - @santi020k/eslint-config-vite@2.0.0-beta.2
64
+ - @santi020k/eslint-config-vue@2.0.0-beta.2
65
+ - @santi020k/eslint-config-preact@2.0.0-beta.2
66
+
67
+ ## 2.0.0-beta.1
68
+
69
+ ### Minor Changes
70
+
71
+ - [`dfba51d`](https://github.com/santi020k/eslint-config-basic/commit/dfba51dca7387a71a263af206eb86fd8df15f387) Thanks [@santi020k](https://github.com/santi020k)! - Improve config migration handling and enhance TypeScript options detection
72
+
73
+ ### Patch Changes
74
+
75
+ - Updated dependencies [[`dfba51d`](https://github.com/santi020k/eslint-config-basic/commit/dfba51dca7387a71a263af206eb86fd8df15f387)]:
76
+ - @santi020k/eslint-config-core@2.0.0-beta.1
77
+ - @santi020k/eslint-config-integrations@2.0.0-beta.1
78
+ - @santi020k/eslint-config-typescript@2.0.0-beta.1
79
+ - @santi020k/eslint-config-angular@2.0.0-beta.1
80
+ - @santi020k/eslint-config-astro@2.0.0-beta.1
81
+ - @santi020k/eslint-config-expo@2.0.0-beta.1
82
+ - @santi020k/eslint-config-hono@2.0.0-beta.1
83
+ - @santi020k/eslint-config-lit@2.0.0-beta.1
84
+ - @santi020k/eslint-config-nest@2.0.0-beta.1
85
+ - @santi020k/eslint-config-next@2.0.0-beta.1
86
+ - @santi020k/eslint-config-nuxt@2.0.0-beta.1
87
+ - @santi020k/eslint-config-qwik@2.0.0-beta.1
88
+ - @santi020k/eslint-config-react@2.0.0-beta.1
89
+ - @santi020k/eslint-config-react-router@2.0.0-beta.1
90
+ - @santi020k/eslint-config-remix@2.0.0-beta.1
91
+ - @santi020k/eslint-config-slidev@2.0.0-beta.1
92
+ - @santi020k/eslint-config-solid@2.0.0-beta.1
93
+ - @santi020k/eslint-config-svelte@2.0.0-beta.1
94
+ - @santi020k/eslint-config-tanstack-start@2.0.0-beta.1
95
+ - @santi020k/eslint-config-vite@2.0.0-beta.1
96
+ - @santi020k/eslint-config-vue@2.0.0-beta.1
97
+ - @santi020k/eslint-config-preact@2.0.0-beta.1
98
+
3
99
  ## 2.0.0-beta.0
4
100
 
5
101
  ### Major Changes
@@ -1,4 +1,7 @@
1
- import { loadModule } from "./lazy.js";
1
+ import {
2
+ createModuleLoader
3
+ } from "@santi020k/eslint-config-core";
4
+ const loadModule = createModuleLoader((specifier) => import.meta.resolve(specifier, import.meta.url));
2
5
  const createDetectedFrameworkFlags = (detectedFrameworks = []) => Object.fromEntries(
3
6
  detectedFrameworks.map((framework) => [framework, true])
4
7
  );
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { EslintConfigOptions, FlatConfigArray } from '@santi020k/eslint-config-core';
1
+ import { EslintConfigOptions, ConfigInput, FlatConfigArray } from '@santi020k/eslint-config-core';
2
2
  export { DetectedFrameworkName, DetectionOptions, EslintConfigOptions, Extension, ExtensionName, ExtensionOption, FlatConfigArray, Format, FormatName, FormatOption, ImportGroupOptions, ImportedFramework, Library, LibraryName, LibraryOption, NextMode, NextModeName, NextModeOption, OptionalConfigMap, OptionalConfigName, Preset, PresetName, PresetOption, ReactConfigKeys, Runtime, RuntimeName, RuntimeOption, Setting, SettingName, SettingOption, StrictMode, Testing, TestingName, TestingOption, Tool, ToolName, ToolOption, TypeScriptMode, TypeScriptOptions, coreConfig, createCoreConfig, createImportGroups, detectProjectOptions, getGlobalsForRuntime, gitignore, groups, hasReactConfig, jsConfig } from '@santi020k/eslint-config-core';
3
- export { AGENT_TARGETS, AgentTarget, GenerateSkillOptions, GenerateSkillResult, generateAgentSkills, generateSkillContent } from './agent-skill-generator.js';
3
+ export { AGENT_TARGETS, AgentTarget, EslintConfigFeatures, GenerateSkillOptions, GenerateSkillResult, generateAgentSkills, generateSkillContent } from './agent-skill-generator.js';
4
4
  export { angular, angularConfig, astro, expo, expoConfig, hono, lit, nest, nestConfig, next, nextConfig, nuxt, preact, preactConfig, qwik, react, reactConfig, reactRouter, remix, slidev, solid, solidConfig, svelte, svelteConfig, tanstackStart, vite, vue, vueConfig } from './frameworks.js';
5
5
  export { a11y, aiSdk, autogen, bestPractices, biome, command, compat, cspell, css, cypress, deMorgan, depend, docker, drizzle, githubActions, googleGenAi, graphql, html, i18next, jest, jestDom, jsdoc, jsonc, langchain, llamaIndex, markdown, mastra, mcp, mdx, mikroOrm, noOnlyTests, node, nx, openAiAgents, oxlint, packageJson, perfectionist, playwright, pnpm, prettier, prisma, regexp, security, sequelize, sonarjs, stencil, storybook, swagger, tailwind, tanstackQuery, tanstackRouter, testingLibrary, toml, turbo, typeorm, unicorn, vitest, yaml, zod } from '@santi020k/eslint-config-integrations';
6
6
  export { tsConfig, typescriptConfig } from '@santi020k/eslint-config-typescript';
@@ -10,12 +10,13 @@ export { tsConfig, typescriptConfig } from '@santi020k/eslint-config-typescript'
10
10
  * and integration settings based on the input configuration.
11
11
  *
12
12
  * @param {EslintConfigOptions} options - Configuration and integration settings
13
+ * @param {ConfigInput[]} extraConfigs - Local flat-config overrides appended after generated config
13
14
  * @returns {FlatConfigArray} The final ESLint configuration array
14
15
  */
15
- declare const eslintConfig: (options?: EslintConfigOptions) => Promise<FlatConfigArray>;
16
+ declare const eslintConfig: (options?: EslintConfigOptions, ...extraConfigs: ConfigInput[]) => Promise<FlatConfigArray>;
16
17
  /**
17
18
  * Alias for `eslintConfig()` that reads naturally in `eslint.config.*` files.
18
19
  */
19
- declare const defineConfig: (options?: EslintConfigOptions) => Promise<FlatConfigArray>;
20
+ declare const defineConfig: (options?: EslintConfigOptions, ...extraConfigs: ConfigInput[]) => Promise<FlatConfigArray>;
20
21
 
21
22
  export { defineConfig, eslintConfig };
package/dist/index.js CHANGED
@@ -1,22 +1,32 @@
1
- import { existsSync } from "node:fs";
2
1
  import { join } from "node:path";
3
2
  import {
3
+ applyDetectionControls,
4
+ applyStrictMode,
5
+ applyStrictProfileDefaults,
4
6
  coreConfig,
5
7
  createCoreConfig,
8
+ DEFAULT_IGNORES,
6
9
  detectProjectOptions,
7
- Extension,
8
- Format,
10
+ findTailwindEntryPoint,
11
+ flattenConfigInputs,
12
+ GENERATED_CODE_IGNORES,
13
+ getStrictMode,
9
14
  gitignore,
10
15
  Library,
16
+ mergeFrameworkOption,
17
+ mergeOptionalBucket,
11
18
  NextMode,
19
+ patchImportGroups,
12
20
  Preset,
21
+ resolveTsconfigRootDir,
22
+ resolveTypescriptOptions,
13
23
  Runtime,
24
+ scopeConfigToProject,
14
25
  Setting,
15
- Testing,
16
- Tool
26
+ Testing
17
27
  } from "@santi020k/eslint-config-core";
28
+ import { tailwind as tailwindIntegration } from "@santi020k/eslint-config-integrations";
18
29
  import { createTypescriptConfig } from "@santi020k/eslint-config-typescript";
19
- import { applyStrictMode } from "./compose.js";
20
30
  import { createDetectedFrameworkFlags } from "./frameworks.js";
21
31
  import { getIntegrationConfigs, getPrettierConfig } from "./integrations.js";
22
32
  import { resolveFramework, resolvePreset } from "./resolvers.js";
@@ -60,8 +70,8 @@ import {
60
70
  createCoreConfig as createCoreConfig2,
61
71
  createImportGroups,
62
72
  detectProjectOptions as detectProjectOptions2,
63
- Extension as Extension2,
64
- Format as Format2,
73
+ Extension,
74
+ Format,
65
75
  getGlobalsForRuntime,
66
76
  gitignore as gitignore2,
67
77
  groups,
@@ -74,7 +84,7 @@ import {
74
84
  Runtime as Runtime2,
75
85
  Setting as Setting2,
76
86
  Testing as Testing2,
77
- Tool as Tool2
87
+ Tool
78
88
  } from "@santi020k/eslint-config-core";
79
89
  import {
80
90
  a11y,
@@ -138,237 +148,70 @@ import {
138
148
  zod
139
149
  } from "@santi020k/eslint-config-integrations";
140
150
  import { tsConfig, typescriptConfig } from "@santi020k/eslint-config-typescript";
141
- const toUniqueArray = (values) => [...new Set(values)];
142
- const DEFAULT_IGNORES = [
143
- "**/dist/**",
144
- "**/build/**",
145
- "**/coverage/**",
146
- "**/.turbo/**",
147
- "**/.next/**",
148
- "**/.open-next/**",
149
- "**/.astro/**",
150
- "**/.svelte-kit/**",
151
- "**/.vercel/**",
152
- "**/.wrangler/**",
153
- "**/playwright-report/**",
154
- "**/test-results/**",
155
- "**/node_modules/**",
156
- "**/tsconfig.tsbuildinfo",
157
- // Package manager lock files (machine-generated, slow to lint)
158
- "**/pnpm-lock.yaml",
159
- "**/yarn.lock",
160
- "**/package-lock.json",
161
- "**/bun.lock",
162
- "**/bun.lockb",
163
- // AI coding-assistant artifacts (rule/skill folders managed by tools, not source code)
164
- "**/.agent/**",
165
- "**/.agents/**",
166
- "**/.aider*",
167
- "**/.aider*/**",
168
- "**/.claude/**",
169
- "**/.clinerules/**",
170
- "**/.codex/**",
171
- "**/.copilot/**",
172
- "**/.cursor/**",
173
- "**/.gemini/**",
174
- "**/.kiro/**",
175
- "**/.opencode/**",
176
- "**/.roo/**",
177
- "**/.windsurf/**"
178
- ];
179
- const GENERATED_CODE_IGNORES = [
180
- "**/__generated__/**",
181
- "**/generated/**",
182
- "**/codegen/**",
183
- "**/*.generated.*",
184
- "**/*.gen.*",
185
- "**/graphql.ts",
186
- "**/graphql.tsx",
187
- "**/gql/**",
188
- "**/.prisma/**"
189
- ];
190
- const TAILWIND_ENTRYPOINT_CANDIDATES = [
191
- "src/styles/global.css",
192
- "src/app/globals.css",
193
- "src/globals.css",
194
- "src/index.css",
195
- "app/globals.css",
196
- "styles/global.css"
197
- ];
198
- const OPTIONAL_BUCKETS = {
199
- extensions: Object.values(Extension),
200
- formats: Object.values(Format),
201
- libraries: Object.values(Library),
202
- testing: Object.values(Testing),
203
- tools: Object.values(Tool)
204
- };
205
- const mergeArrayOption = (detectedValues, presetValues, explicitValues, strategy) => {
206
- if (strategy === "replace") {
207
- if (explicitValues) return toUniqueArray(explicitValues);
208
- if (presetValues) return toUniqueArray(presetValues);
209
- return toUniqueArray(detectedValues);
210
- }
211
- return toUniqueArray([
212
- ...detectedValues,
213
- ...presetValues ?? [],
214
- ...explicitValues ?? []
215
- ]);
151
+ const buildTailwindResult = (options, entryPoint) => ({
152
+ detectComponentClasses: options.detectComponentClasses ?? true,
153
+ ...entryPoint ? { entryPoint } : {},
154
+ ...options.ignore?.length ? { ignore: options.ignore } : {},
155
+ ...options.noUnknownClasses === void 0 ? {} : { noUnknownClasses: options.noUnknownClasses }
156
+ });
157
+ const resolveTailwindOptions = (rootDir, tailwind2) => {
158
+ if (tailwind2 === false) return void 0;
159
+ const options = tailwind2 ?? {};
160
+ const entryPoint = options.entryPoint ?? findTailwindEntryPoint(rootDir);
161
+ if (!entryPoint && options.detectComponentClasses === void 0 && !options.ignore?.length && options.noUnknownClasses === void 0) return void 0;
162
+ return buildTailwindResult(options, entryPoint);
216
163
  };
217
- const isOptionalBucketValue = (bucket, value) => OPTIONAL_BUCKETS[bucket].includes(value);
218
- const getFeatureEntries = (options, bucket, enabled) => [
219
- ...Object.entries(options?.features ?? {}),
220
- ...Object.entries(options?.integrations ?? {})
221
- ].filter(([name, value]) => value === enabled && isOptionalBucketValue(bucket, name)).map(([name]) => name);
222
- const applyFeatureDisables = (values, options, bucket) => {
223
- const disabled = new Set(getFeatureEntries(options, bucket, false));
224
- return values.filter((value) => !disabled.has(value));
164
+ const createNoUnknownClassesRule = (tailwindOptions, unknownClassOptions, hasUnknownClassOptions) => {
165
+ if (!hasUnknownClassOptions && tailwindOptions.noUnknownClasses === void 0) return void 0;
166
+ const severity = tailwindOptions.noUnknownClasses ?? "error";
167
+ if (severity === false) return "off";
168
+ return hasUnknownClassOptions ? [severity, unknownClassOptions] : severity;
225
169
  };
226
- const mergeOptionalBucket = (bucket, detectedValues, presetValues, explicitValues, options, strategy) => {
227
- const featureEntries = getFeatureEntries(options, bucket, true);
228
- const combined = explicitValues !== void 0 || featureEntries.length > 0 ? [...explicitValues ?? [], ...featureEntries] : void 0;
229
- return applyFeatureDisables(
230
- mergeArrayOption(detectedValues, presetValues, combined, strategy),
231
- options,
232
- bucket
233
- );
234
- };
235
- const mergeFrameworkOption = (detectedFrameworks, presetFrameworks, explicitFrameworks, strategy) => {
236
- if (strategy === "replace") {
237
- if (explicitFrameworks) return { ...explicitFrameworks };
238
- if (presetFrameworks) return { ...presetFrameworks };
239
- return { ...detectedFrameworks };
240
- }
241
- return {
242
- ...detectedFrameworks,
243
- ...presetFrameworks ?? {},
244
- ...explicitFrameworks ?? {}
245
- };
170
+ const loadTailwindPlugins = async () => {
171
+ const tailwindConfigs = await tailwindIntegration();
172
+ const pluginConfig = tailwindConfigs.find((config) => config.plugins?.["better-tailwindcss"]);
173
+ return pluginConfig?.plugins ?? {};
246
174
  };
247
- const resolveDetectionOptions = (detection, defaults = {}) => {
248
- const defaultControls = {
249
- extensions: true,
250
- formats: true,
251
- frameworks: true,
252
- libraries: true,
253
- nextMode: true,
254
- projects: false,
255
- runtime: true,
256
- testing: true,
257
- tools: true,
258
- typescript: true,
259
- ...defaults
175
+ const createTailwindSettingsConfig = async (tailwindOptions) => {
176
+ const { noUnknownClasses: _noUnknownClasses, ...settingsOptions } = tailwindOptions;
177
+ const unknownClassOptions = {
178
+ ...tailwindOptions.entryPoint ? { entryPoint: tailwindOptions.entryPoint } : {},
179
+ ...tailwindOptions.ignore?.length ? { ignore: tailwindOptions.ignore } : {}
260
180
  };
261
- if (detection === false) {
262
- return Object.fromEntries(
263
- Object.keys(defaultControls).map((key) => [key, false])
264
- );
265
- }
266
- if (detection === true || detection === void 0) {
267
- return defaultControls;
268
- }
269
- return {
270
- ...defaultControls,
271
- ...detection
272
- };
273
- };
274
- const applyArrayControls = (controls, detected) => ({
275
- detectedFrameworks: controls.frameworks ? detected.detectedFrameworks : [],
276
- extensions: controls.extensions ? detected.extensions : [],
277
- formats: controls.formats ? detected.formats : [],
278
- libraries: controls.libraries ? detected.libraries : [],
279
- testing: controls.testing ? detected.testing : [],
280
- tools: controls.tools ? detected.tools : []
281
- });
282
- const applyScalarControls = (controls, detected) => ({
283
- nextMode: controls.nextMode ? detected.nextMode : void 0,
284
- preset: controls.typescript && controls.runtime ? detected.preset : void 0,
285
- projects: controls.projects ? detected.projects : void 0,
286
- runtime: controls.runtime ? detected.runtime : void 0,
287
- typescript: controls.typescript ? detected.typescript : false
288
- });
289
- const applyDetectionControls = (detected, detection, defaults) => {
290
- const controls = resolveDetectionOptions(detection, defaults);
291
- return { ...detected, ...applyArrayControls(controls, detected), ...applyScalarControls(controls, detected) };
292
- };
293
- const getStrictMode = (explicitStrict, presetStrict) => explicitStrict ?? presetStrict ?? false;
294
- const applyStrictProfileDefaults = (extensions, strict) => {
295
- if (strict !== "pedantic") return extensions;
296
- return toUniqueArray([...extensions, Extension.BestPractices]);
297
- };
298
- const hasTsconfig = (rootDir) => [
299
- "tsconfig.eslint.json",
300
- "tsconfig.json",
301
- "tsconfig.base.json",
302
- "tsconfig.app.json",
303
- "tsconfig.node.json"
304
- ].some((fileName) => existsSync(join(rootDir, fileName)));
305
- const resolveTypescriptOptions = (typescript) => {
306
- if (!typescript || typescript === "off") return false;
307
- if (typescript === true) return { mode: "type-aware" };
308
- if (typeof typescript === "string") return { mode: typescript };
309
- if (typescript.mode === "off") return false;
181
+ const hasUnknownClassOptions = Object.keys(unknownClassOptions).length > 0;
182
+ const noUnknownClassesRule = createNoUnknownClassesRule(tailwindOptions, unknownClassOptions, hasUnknownClassOptions);
310
183
  return {
311
- ...typescript,
312
- mode: typescript.mode ?? "type-aware"
184
+ name: "eslint-config-basic/tailwind-settings",
185
+ plugins: await loadTailwindPlugins(),
186
+ ...noUnknownClassesRule === void 0 ? {} : { rules: { "better-tailwindcss/no-unknown-classes": noUnknownClassesRule } },
187
+ settings: {
188
+ "better-tailwindcss": settingsOptions
189
+ }
313
190
  };
314
191
  };
315
- const resolveTsconfigRootDir = (rootDir, typescript, explicitRootDir) => {
316
- if (explicitRootDir) return explicitRootDir;
317
- return resolveTypescriptOptions(typescript) && hasTsconfig(rootDir) ? rootDir : void 0;
192
+ const TESTING_CONFIG_NAMES = {
193
+ [Testing.Cypress]: ["integrations/cypress"],
194
+ [Testing.Jest]: ["integrations/jest"],
195
+ [Testing.JestDom]: ["eslint-config-integrations/jest-dom"],
196
+ [Testing.Playwright]: ["integrations/playwright"],
197
+ [Testing.TestingLibrary]: ["integrations/testing-library"],
198
+ [Testing.Vitest]: ["integrations/vitest"]
318
199
  };
319
- const findTailwindEntryPoint = (rootDir) => TAILWIND_ENTRYPOINT_CANDIDATES.find(
320
- (candidate) => existsSync(join(rootDir, candidate))
321
- );
322
- const scopeFilePattern = (projectPath, pattern) => {
323
- if (typeof pattern === "string") {
324
- const isNegated = pattern.startsWith("!");
325
- const basePattern = (isNegated ? pattern.slice(1) : pattern).replace(/^\.\//, "");
326
- const scoped = `${projectPath.replace(/\/$/, "")}/${basePattern}`;
327
- return isNegated ? `!${scoped}` : scoped;
328
- }
329
- if (Array.isArray(pattern)) {
330
- return pattern.map((item) => scopeFilePattern(projectPath, item));
331
- }
332
- return pattern;
333
- };
334
- const scopeConfigToProject = (config, projectPath) => {
335
- if ("ignores" in config && !config.files) {
200
+ const applyTestingFileOverrides = (configs, testingFiles) => {
201
+ if (!testingFiles) return configs;
202
+ const entries = Object.entries(testingFiles).filter(([, files]) => files.length > 0);
203
+ if (entries.length === 0) return configs;
204
+ return configs.map((config) => {
205
+ const match = entries.find(
206
+ ([testingName]) => (TESTING_CONFIG_NAMES[testingName] ?? []).includes(config.name ?? "")
207
+ );
208
+ if (!match) return config;
209
+ const [, files] = match;
336
210
  return {
337
211
  ...config,
338
- ignores: config.ignores?.map((pattern) => scopeFilePattern(projectPath, pattern))
212
+ files
339
213
  };
340
- }
341
- return {
342
- ...config,
343
- files: Array.isArray(config.files) ? config.files.map((pattern) => scopeFilePattern(projectPath, pattern)) : [`${projectPath.replace(/\/$/, "")}/**/*`]
344
- };
345
- };
346
- const patchImportGroupsConfig = (config, workspacePatterns) => {
347
- const rule = config.rules?.["simple-import-sort/imports"];
348
- if (!Array.isArray(rule) || !rule[1]) return config;
349
- const ruleOpts = rule[1];
350
- const existingGroups = ruleOpts.groups ?? [];
351
- if (existingGroups.length === 0) return config;
352
- const externalIdx = existingGroups.findIndex((g) => g.some((p) => p.includes("^@?\\w")));
353
- const insertAt = externalIdx >= 0 ? externalIdx : existingGroups.length;
354
- return {
355
- ...config,
356
- rules: {
357
- ...config.rules,
358
- "simple-import-sort/imports": [
359
- rule[0],
360
- { ...ruleOpts, groups: [...existingGroups.slice(0, insertAt), workspacePatterns, ...existingGroups.slice(insertAt)] }
361
- ]
362
- }
363
- };
364
- };
365
- const patchImportGroups = (allConfigs, workspacePrefixes) => {
366
- const workspacePatterns = workspacePrefixes.map(
367
- (p) => `^${p.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&")}(/.*|$)`
368
- );
369
- return allConfigs.map(
370
- (item) => Array.isArray(item) ? item : patchImportGroupsConfig(item, workspacePatterns)
371
- );
214
+ });
372
215
  };
373
216
  const resolveConfigSetup = (options) => ({
374
217
  autoFrameworks: options?.autoFrameworks ?? true,
@@ -376,6 +219,12 @@ const resolveConfigSetup = (options) => ({
376
219
  optionMergeStrategy: options?.optionMergeStrategy ?? "merge",
377
220
  requestedPreset: options?.preset
378
221
  });
222
+ const resolveUniqueLibraries = (libraries, tailwind2) => {
223
+ const uniqueLibraries = [...new Set(libraries)];
224
+ if (tailwind2 === false) return uniqueLibraries.filter((library) => library !== Library.Tailwind);
225
+ if (!tailwind2) return uniqueLibraries;
226
+ return [.../* @__PURE__ */ new Set([...uniqueLibraries, Library.Tailwind])];
227
+ };
379
228
  const resolvePresetMeta = (requestedPreset, detected, autoFrameworks) => {
380
229
  const preset = requestedPreset ?? detected.preset;
381
230
  const presetDefaults = preset ? resolvePreset(preset) : {};
@@ -418,6 +267,23 @@ const buildIgnoresConfig = (useDefaultIgnores, useGeneratedCodeIgnores, useGitig
418
267
  name: "eslint-config-basic/ignores"
419
268
  }] : []
420
269
  });
270
+ const FRAMEWORK_EXTRA_OPTS = {
271
+ astro: (ctx) => ({ hasReact: ctx.hasReact, hasSolid: ctx.hasSolid, hasSvelte: ctx.hasSvelte, hasVue: ctx.hasVue }),
272
+ hono: (ctx) => ({ runtime: ctx.runtime }),
273
+ slidev: (ctx) => ({ runtime: ctx.runtime }),
274
+ vite: (ctx) => ({ runtime: ctx.runtime })
275
+ };
276
+ const resolveEnabledFrameworks = async (frameworks, ctx) => {
277
+ const entries = await Promise.all(
278
+ Object.entries(frameworks).filter((entry) => Boolean(entry[1])).map(
279
+ ([name, value]) => (
280
+ // eslint-disable-next-line security/detect-object-injection
281
+ resolveFramework(name, value, FRAMEWORK_EXTRA_OPTS[name]?.(ctx)).then((config) => [name, config])
282
+ )
283
+ )
284
+ );
285
+ return Object.fromEntries(entries);
286
+ };
421
287
  const buildEslintConfigs = async (params) => {
422
288
  const {
423
289
  astroOptions,
@@ -429,7 +295,8 @@ const buildEslintConfigs = async (params) => {
429
295
  rootDir: _rootDir,
430
296
  runtime,
431
297
  runtimeCoreConfig,
432
- tailwindEntryPoint,
298
+ tailwindOptions,
299
+ testingFiles,
433
300
  tsconfigRootDir,
434
301
  uniqueExtensions,
435
302
  uniqueFormats,
@@ -439,47 +306,8 @@ const buildEslintConfigs = async (params) => {
439
306
  userIgnores
440
307
  } = params;
441
308
  const { hasReact, hasSolid, hasSvelte, hasVue } = astroOptions;
442
- const [
443
- reactParam,
444
- nextParam,
445
- astroParam,
446
- expoParam,
447
- nestParam,
448
- honoParam,
449
- vueParam,
450
- svelteParam,
451
- solidParam,
452
- angularParam,
453
- qwikParam,
454
- remixParam,
455
- reactRouterParam,
456
- tanstackStartParam,
457
- nuxtParam,
458
- preactParam,
459
- litParam,
460
- slidevParam,
461
- viteParam
462
- ] = await Promise.all([
463
- resolveFramework("react", resolvedFrameworks.react),
464
- resolveFramework("next", resolvedFrameworks.next),
465
- resolveFramework("astro", resolvedFrameworks.astro, { hasReact, hasSolid, hasSvelte, hasVue }),
466
- resolveFramework("expo", resolvedFrameworks.expo),
467
- resolveFramework("nest", resolvedFrameworks.nest),
468
- resolveFramework("hono", resolvedFrameworks.hono, { runtime }),
469
- resolveFramework("vue", resolvedFrameworks.vue),
470
- resolveFramework("svelte", resolvedFrameworks.svelte),
471
- resolveFramework("solid", resolvedFrameworks.solid),
472
- resolveFramework("angular", resolvedFrameworks.angular),
473
- resolveFramework("qwik", resolvedFrameworks.qwik),
474
- resolveFramework("remix", resolvedFrameworks.remix),
475
- resolveFramework("react-router", resolvedFrameworks["react-router"]),
476
- resolveFramework("tanstack-start", resolvedFrameworks["tanstack-start"]),
477
- resolveFramework("nuxt", resolvedFrameworks.nuxt),
478
- resolveFramework("preact", resolvedFrameworks.preact),
479
- resolveFramework("lit", resolvedFrameworks.lit),
480
- resolveFramework("slidev", resolvedFrameworks.slidev, { runtime }),
481
- resolveFramework("vite", resolvedFrameworks.vite, { runtime })
482
- ]);
309
+ const fw = await resolveEnabledFrameworks(resolvedFrameworks, { hasReact, hasSolid, hasSvelte, hasVue, runtime });
310
+ const get = (name) => fw[name] ?? [];
483
311
  return [
484
312
  ...defaultIgnores,
485
313
  ...userIgnores,
@@ -503,48 +331,58 @@ const buildEslintConfigs = async (params) => {
503
331
  name: "eslint-config-basic/commonjs"
504
332
  },
505
333
  ...runtimeCoreConfig,
506
- ...hasReact ? reactParam : [],
507
- ...nextParam,
508
- ...expoParam,
509
- ...nestParam,
510
- ...honoParam,
511
- ...vueParam,
512
- ...svelteParam,
513
- ...solidParam,
514
- ...angularParam,
515
- ...qwikParam,
516
- ...remixParam,
517
- ...reactRouterParam,
518
- ...tanstackStartParam,
519
- ...nuxtParam,
520
- ...preactParam,
521
- ...litParam,
522
- ...slidevParam,
523
- ...viteParam,
334
+ ...hasReact ? get("react") : [],
335
+ ...get("next"),
336
+ ...get("expo"),
337
+ ...get("nest"),
338
+ ...get("hono"),
339
+ ...get("vue"),
340
+ ...get("svelte"),
341
+ ...get("solid"),
342
+ ...get("angular"),
343
+ ...get("qwik"),
344
+ ...get("remix"),
345
+ ...get("react-router"),
346
+ ...get("tanstack-start"),
347
+ ...get("nuxt"),
348
+ ...get("preact"),
349
+ ...get("lit"),
350
+ ...get("slidev"),
351
+ ...get("vite"),
524
352
  ...resolvedTypescript ? createTypescriptConfig({
525
353
  ...resolvedTypescript,
526
354
  tsconfigRootDir: resolvedTypescript.tsconfigRootDir ?? tsconfigRootDir
527
355
  }) : [],
528
- ...astroParam,
356
+ ...get("astro"),
529
357
  ...resolvedFrameworks.next && nextMode === NextMode.AppRouter ? [{
530
358
  files: ["app/**/*.{ts,tsx}", "src/**/*.{ts,tsx}"],
531
359
  name: "eslint-config-next/app-router-overrides",
532
360
  rules: { "@next/next/no-html-link-for-pages": "off" }
533
361
  }] : [],
534
- ...await getIntegrationConfigs(uniqueLibraries, uniqueTools, uniqueTesting, uniqueFormats, uniqueExtensions),
535
- ...tailwindEntryPoint ? [{
536
- name: "eslint-config-basic/tailwind-settings",
537
- settings: {
538
- "better-tailwindcss": {
539
- detectComponentClasses: true,
540
- entryPoint: tailwindEntryPoint
541
- }
542
- }
543
- }] : [],
362
+ ...applyTestingFileOverrides(
363
+ await getIntegrationConfigs(uniqueLibraries, uniqueTools, uniqueTesting, uniqueFormats, uniqueExtensions),
364
+ testingFiles
365
+ ),
366
+ ...tailwindOptions ? [await createTailwindSettingsConfig(tailwindOptions)] : [],
544
367
  ...await getPrettierConfig(uniqueTools)
545
368
  ];
546
369
  };
547
- const logEslintDebug = (autoFrameworks, detectRootDir, nextMode, optionMergeStrategy, preset, resolvedFrameworks, resolvedTypescript, runtime, tsconfigRootDir, uniqueExtensions, uniqueFormats, uniqueLibraries, uniqueTesting, uniqueTools) => {
370
+ const logEslintDebug = ({
371
+ autoFrameworks,
372
+ detectRootDir,
373
+ nextMode,
374
+ optionMergeStrategy,
375
+ preset,
376
+ resolvedFrameworks,
377
+ resolvedTypescript,
378
+ runtime,
379
+ tsconfigRootDir,
380
+ uniqueExtensions,
381
+ uniqueFormats,
382
+ uniqueLibraries,
383
+ uniqueTesting,
384
+ uniqueTools
385
+ }) => {
548
386
  if (!process.env.ESLINT_BASIC_DEBUG) return;
549
387
  process.stdout.write(`[ESLint Basic] Resolved options: ${JSON.stringify({
550
388
  autoFrameworks,
@@ -564,7 +402,16 @@ const logEslintDebug = (autoFrameworks, detectRootDir, nextMode, optionMergeStra
564
402
  }, null, 2)}
565
403
  `);
566
404
  };
567
- const eslintConfig = async (options) => {
405
+ const emitBasicWarnings = (options) => {
406
+ if (options?.frameworks && "remix" in options.frameworks) {
407
+ process.emitWarning('[eslint-config-basic] Warning: `frameworks.remix` is deprecated and will be removed in the next major. Please use `frameworks["react-router"]` instead.');
408
+ }
409
+ if (options?.typescript && typeof options.typescript === "object" && "project" in options.typescript) {
410
+ process.emitWarning("[eslint-config-basic] Warning: `typescript.project` is ignored in v2. Type-aware linting now relies on typescript-eslint projectService.");
411
+ }
412
+ };
413
+ const eslintConfig = async (options, ...extraConfigs) => {
414
+ emitBasicWarnings(options);
568
415
  const {
569
416
  detection,
570
417
  extensions: optExtensions,
@@ -638,7 +485,7 @@ const eslintConfig = async (options) => {
638
485
  const tsconfigRootDir = resolveTsconfigRootDir(rootDir, typescript, optTsconfigRootDir);
639
486
  const extensions = applyStrictProfileDefaults(configuredExtensions, strict);
640
487
  const resolvedFrameworks = applyFrameworkImpliedDeps({ ...frameworks });
641
- const uniqueLibraries = [...new Set(libraries)];
488
+ const uniqueLibraries = resolveUniqueLibraries(libraries, options?.tailwind);
642
489
  const uniqueTesting = [...new Set(testing)];
643
490
  const uniqueFormats = [...new Set(formats)];
644
491
  const uniqueTools = [...new Set(tools)];
@@ -651,7 +498,7 @@ const eslintConfig = async (options) => {
651
498
  const useGitignore = !uniqueSettings.includes(Setting.NoGitignore);
652
499
  const useDefaultIgnores = !uniqueSettings.includes(Setting.NoDefaultIgnores);
653
500
  const useGeneratedCodeIgnores = !uniqueSettings.includes(Setting.NoGeneratedCodeIgnores);
654
- const tailwindEntryPoint = uniqueLibraries.includes(Library.Tailwind) ? findTailwindEntryPoint(rootDir) : void 0;
501
+ const tailwindOptions = uniqueLibraries.includes(Library.Tailwind) ? resolveTailwindOptions(rootDir, options?.tailwind) : void 0;
655
502
  const runtimeCoreConfig = runtime === Runtime.Universal ? coreConfig : createCoreConfig(runtime);
656
503
  const { defaultIgnores, gitignoreConfig, userIgnores } = buildIgnoresConfig(useDefaultIgnores, useGeneratedCodeIgnores, useGitignore, options);
657
504
  const configs = await buildEslintConfigs({
@@ -664,7 +511,8 @@ const eslintConfig = async (options) => {
664
511
  rootDir,
665
512
  runtime,
666
513
  runtimeCoreConfig,
667
- tailwindEntryPoint,
514
+ tailwindOptions,
515
+ testingFiles: options?.testingFiles,
668
516
  tsconfigRootDir,
669
517
  uniqueExtensions,
670
518
  uniqueFormats,
@@ -673,7 +521,7 @@ const eslintConfig = async (options) => {
673
521
  uniqueTools,
674
522
  userIgnores
675
523
  });
676
- logEslintDebug(
524
+ logEslintDebug({
677
525
  autoFrameworks,
678
526
  detectRootDir,
679
527
  nextMode,
@@ -688,11 +536,12 @@ const eslintConfig = async (options) => {
688
536
  uniqueLibraries,
689
537
  uniqueTesting,
690
538
  uniqueTools
691
- );
539
+ });
692
540
  const projectConfigs = await Promise.all(
693
541
  Object.entries(configuredProjects).map(async ([projectPath, projectOptions]) => {
694
542
  const projectRoot = join(detectRootDir ?? process.cwd(), projectPath);
695
543
  const scopedConfigs = await eslintConfig({
544
+ autoFrameworks: options?.autoFrameworks,
696
545
  ...projectOptions,
697
546
  detectRootDir: projectOptions.detectRootDir ?? projectRoot,
698
547
  projects: void 0,
@@ -701,15 +550,15 @@ const eslintConfig = async (options) => {
701
550
  return scopedConfigs.map((config) => scopeConfigToProject(config, projectPath));
702
551
  })
703
552
  );
704
- const allConfigs = [...configs, ...projectConfigs.flat()];
553
+ const allConfigs = [...configs, ...projectConfigs.flat(), ...flattenConfigInputs(extraConfigs)];
705
554
  const patchedConfigs = workspacePrefixes?.length ? patchImportGroups(allConfigs, workspacePrefixes) : allConfigs;
706
555
  return applyStrictMode(patchedConfigs, strict);
707
556
  };
708
557
  const defineConfig = eslintConfig;
709
558
  export {
710
559
  AGENT_TARGETS,
711
- Extension2 as Extension,
712
- Format2 as Format,
560
+ Extension,
561
+ Format,
713
562
  Library2 as Library,
714
563
  NextMode2 as NextMode,
715
564
  Preset2 as Preset,
@@ -717,7 +566,7 @@ export {
717
566
  Runtime2 as Runtime,
718
567
  Setting2 as Setting,
719
568
  Testing2 as Testing,
720
- Tool2 as Tool,
569
+ Tool,
721
570
  a11y,
722
571
  aiSdk,
723
572
  angular,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@santi020k/eslint-config-basic",
3
- "version": "2.0.0-beta.0",
3
+ "version": "2.0.0-beta.3",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -30,30 +30,31 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@typescript-eslint/utils": "^8.61.1",
33
- "@santi020k/eslint-config-angular": "^2.0.0-beta.0",
34
- "@santi020k/eslint-config-astro": "^2.0.0-beta.0",
35
- "@santi020k/eslint-config-core": "^2.0.0-beta.0",
36
- "@santi020k/eslint-config-expo": "^2.0.0-beta.0",
37
- "@santi020k/eslint-config-hono": "^2.0.0-beta.0",
38
- "@santi020k/eslint-config-integrations": "^2.0.0-beta.0",
39
- "@santi020k/eslint-config-lit": "^2.0.0-beta.0",
40
- "@santi020k/eslint-config-nest": "^2.0.0-beta.0",
41
- "@santi020k/eslint-config-next": "^2.0.0-beta.0",
42
- "@santi020k/eslint-config-nuxt": "^2.0.0-beta.0",
43
- "@santi020k/eslint-config-preact": "^2.0.0-beta.0",
44
- "@santi020k/eslint-config-qwik": "^2.0.0-beta.0",
45
- "@santi020k/eslint-config-react": "^2.0.0-beta.0",
46
- "@santi020k/eslint-config-react-router": "^2.0.0-beta.0",
47
- "@santi020k/eslint-config-remix": "^2.0.0-beta.0",
48
- "@santi020k/eslint-config-slidev": "^2.0.0-beta.0",
49
- "@santi020k/eslint-config-solid": "^2.0.0-beta.0",
50
- "@santi020k/eslint-config-svelte": "^2.0.0-beta.0",
51
- "@santi020k/eslint-config-tanstack-start": "^2.0.0-beta.0",
52
- "@santi020k/eslint-config-typescript": "^2.0.0-beta.0",
53
- "@santi020k/eslint-config-vite": "^2.0.0-beta.0",
54
- "@santi020k/eslint-config-vue": "^2.0.0-beta.0"
33
+ "@santi020k/eslint-config-angular": "^2.0.0-beta.3",
34
+ "@santi020k/eslint-config-astro": "^2.0.0-beta.3",
35
+ "@santi020k/eslint-config-core": "^2.0.0-beta.3",
36
+ "@santi020k/eslint-config-expo": "^2.0.0-beta.3",
37
+ "@santi020k/eslint-config-hono": "^2.0.0-beta.3",
38
+ "@santi020k/eslint-config-integrations": "^2.0.0-beta.3",
39
+ "@santi020k/eslint-config-lit": "^2.0.0-beta.3",
40
+ "@santi020k/eslint-config-nest": "^2.0.0-beta.3",
41
+ "@santi020k/eslint-config-next": "^2.0.0-beta.3",
42
+ "@santi020k/eslint-config-nuxt": "^2.0.0-beta.3",
43
+ "@santi020k/eslint-config-preact": "^2.0.0-beta.3",
44
+ "@santi020k/eslint-config-qwik": "^2.0.0-beta.3",
45
+ "@santi020k/eslint-config-react": "^2.0.0-beta.3",
46
+ "@santi020k/eslint-config-react-router": "^2.0.0-beta.3",
47
+ "@santi020k/eslint-config-remix": "^2.0.0-beta.3",
48
+ "@santi020k/eslint-config-slidev": "^2.0.0-beta.3",
49
+ "@santi020k/eslint-config-solid": "^2.0.0-beta.3",
50
+ "@santi020k/eslint-config-svelte": "^2.0.0-beta.3",
51
+ "@santi020k/eslint-config-tanstack-start": "^2.0.0-beta.3",
52
+ "@santi020k/eslint-config-typescript": "^2.0.0-beta.3",
53
+ "@santi020k/eslint-config-vite": "^2.0.0-beta.3",
54
+ "@santi020k/eslint-config-vue": "^2.0.0-beta.3"
55
55
  },
56
56
  "devDependencies": {
57
+ "@types/node": "^25.9.3",
57
58
  "publint": "^0.3.21",
58
59
  "tsup": "^8.5.1",
59
60
  "typescript": "^6.0.3"
package/dist/compose.d.ts DELETED
@@ -1,10 +0,0 @@
1
- import { FlatConfigArray } from '@santi020k/eslint-config-core';
2
-
3
- type NormalizedStrictMode = 'ci' | 'pedantic' | 'recommended';
4
- declare const normalizeStrictMode: (strict: boolean | NormalizedStrictMode | undefined) => NormalizedStrictMode;
5
- /**
6
- * Applies strict mode by promoting all 'warn' rules to 'error'.
7
- */
8
- declare const applyStrictMode: (configs: FlatConfigArray, strict: boolean | NormalizedStrictMode | undefined) => FlatConfigArray;
9
-
10
- export { type NormalizedStrictMode, applyStrictMode, normalizeStrictMode };
package/dist/compose.js DELETED
@@ -1,34 +0,0 @@
1
- const normalizeStrictMode = (strict) => {
2
- if (strict === true) return "ci";
3
- if (strict === "ci" || strict === "pedantic") return strict;
4
- return "recommended";
5
- };
6
- const promoteRuleSeverity = (value) => {
7
- if (value === void 0) return void 0;
8
- if (value === "warn" || value === 1) return "error";
9
- if (Array.isArray(value) && (value[0] === "warn" || value[0] === 1)) {
10
- return ["error", ...value.slice(1)];
11
- }
12
- return value;
13
- };
14
- const applyStrictMode = (configs, strict) => {
15
- const strictMode = normalizeStrictMode(strict);
16
- if (strictMode === "recommended") return configs;
17
- const recurse = (item) => {
18
- if (Array.isArray(item)) {
19
- return item.map((config) => recurse(config));
20
- }
21
- if (item.rules) {
22
- const strictRules = Object.fromEntries(
23
- Object.entries(item.rules).map(([key, value]) => [key, promoteRuleSeverity(value)])
24
- );
25
- return { ...item, rules: strictRules };
26
- }
27
- return item;
28
- };
29
- return recurse(configs);
30
- };
31
- export {
32
- applyStrictMode,
33
- normalizeStrictMode
34
- };
package/dist/lazy.d.ts DELETED
@@ -1,3 +0,0 @@
1
- declare const loadModule: <T = unknown>(specifier: string) => Promise<T>;
2
-
3
- export { loadModule };
package/dist/lazy.js DELETED
@@ -1,19 +0,0 @@
1
- import { createRequire } from "node:module";
2
- import { pathToFileURL } from "node:url";
3
- const isVitest = typeof process !== "undefined" && process.env.VITEST;
4
- const dynamicImport = isVitest ? (specifier) => import(
5
- /* @vite-ignore */
6
- specifier
7
- ) : Reflect.construct(Function, ["specifier", "return import(specifier)"]);
8
- const req = createRequire(import.meta.url);
9
- const loadModule = async (specifier) => {
10
- let resolved = specifier;
11
- try {
12
- resolved = pathToFileURL(req.resolve(specifier)).href;
13
- } catch {
14
- }
15
- return await dynamicImport(resolved);
16
- };
17
- export {
18
- loadModule
19
- };