proteum 2.5.9 → 2.5.11
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 +4 -4
- package/agents/project/AGENTS.md +131 -91
- package/agents/project/CODING_STYLE.md +69 -40
- package/agents/project/DOCUMENTATION.md +19 -2
- package/agents/project/client/AGENTS.md +0 -1
- package/agents/project/diagnostics.md +6 -5
- package/agents/project/optimizations.md +1 -7
- package/agents/project/server/services/AGENTS.md +1 -3
- package/agents/project/tests/AGENTS.md +3 -3
- package/cli/commands/docs.ts +223 -0
- package/cli/commands/session.ts +36 -5
- package/cli/commands/verify.ts +6 -1
- package/cli/compiler/client/index.ts +11 -4
- package/cli/compiler/common/uiSingletons.ts +76 -0
- package/cli/compiler/server/index.ts +34 -12
- package/cli/presentation/commands.ts +20 -1
- package/cli/runtime/commands.ts +20 -0
- package/cli/scaffold/index.ts +3 -0
- package/cli/scaffold/templates.ts +62 -6
- package/cli/utils/agents.ts +2 -2
- package/cli/verification/changed.ts +21 -0
- package/client/dev/profiler/index.tsx +761 -455
- package/common/dev/mcpPayloads.ts +86 -8
- package/common/dev/session.ts +32 -0
- package/common/errors/index.tsx +0 -1
- package/docAnchors.js +135 -0
- package/docs/agent-routing.md +2 -2
- package/eslint.js +264 -1
- package/package.json +1 -1
- package/server/app/container/console/index.ts +0 -17
- package/server/services/router/http/index.ts +130 -33
- package/tests/agents-utils.test.cjs +0 -4
- package/tests/dev-session-login-url.test.cjs +33 -0
- package/tests/doc-anchors.test.cjs +115 -0
- package/tests/docs-check.test.cjs +138 -0
- package/tests/eslint-rules.test.cjs +235 -2
- package/tests/mcp.test.cjs +109 -0
- package/tests/ui-singletons.test.cjs +104 -0
- package/tests/verify-changed.test.cjs +51 -3
- package/agents/project/app-root/AGENTS.md +0 -14
- package/agents/project/root/AGENTS.md +0 -399
|
@@ -10,6 +10,11 @@ import { type Configuration } from '@rspack/core';
|
|
|
10
10
|
import cli from '@cli';
|
|
11
11
|
import createCommonConfig, { TCompileMode, TCompileOutputTarget, regex } from '../common';
|
|
12
12
|
import { toRspackAliases } from '../common/rspackAliases';
|
|
13
|
+
import {
|
|
14
|
+
isUiSingletonRequest,
|
|
15
|
+
resolveUiSingletonAliases,
|
|
16
|
+
resolveUiSingletonServerExternalRequest,
|
|
17
|
+
} from '../common/uiSingletons';
|
|
13
18
|
import { resolveServerExternalRequest } from './externals';
|
|
14
19
|
|
|
15
20
|
// Type
|
|
@@ -51,6 +56,9 @@ const getDevGeneratedRuntimeEntries = (app: App) => ({
|
|
|
51
56
|
__proteum_dev_routes: [app.paths.server.generated + '/routes.ts'],
|
|
52
57
|
__proteum_dev_controllers: [app.paths.server.generated + '/controllers.ts'],
|
|
53
58
|
});
|
|
59
|
+
const resolveFromAppOrCore = (request: string) => cli.paths.resolveRequest(request, { preferApp: true });
|
|
60
|
+
const resolvePackageRootFromAppOrCore = (packageName: string) =>
|
|
61
|
+
cli.paths.resolvePackageRoot(packageName, { preferApp: true });
|
|
54
62
|
const normalizeModulePath = (value?: string) => (value || '').replace(/\\/g, '/');
|
|
55
63
|
const getFrameworkSourceRoot = () => {
|
|
56
64
|
const installedCoreRoot = cli.paths.framework.installedRoot
|
|
@@ -120,6 +128,13 @@ export default function createCompiler(
|
|
|
120
128
|
const rspackAliases = toRspackAliases(resolvedAliases);
|
|
121
129
|
rspackAliases['proteum'] = frameworkSourceRoot;
|
|
122
130
|
rspackAliases['@/client/router$'] = frameworkSourceRoot + '/client/router.ts';
|
|
131
|
+
Object.assign(
|
|
132
|
+
rspackAliases,
|
|
133
|
+
resolveUiSingletonAliases({
|
|
134
|
+
resolvePackageRoot: resolvePackageRootFromAppOrCore,
|
|
135
|
+
resolveRequest: resolveFromAppOrCore,
|
|
136
|
+
}),
|
|
137
|
+
);
|
|
123
138
|
|
|
124
139
|
debug &&
|
|
125
140
|
console.log(
|
|
@@ -160,20 +175,27 @@ export default function createCompiler(
|
|
|
160
175
|
|
|
161
176
|
// node_modules
|
|
162
177
|
function ({ context, request }, callback) {
|
|
178
|
+
if (request === undefined) return callback();
|
|
179
|
+
|
|
180
|
+
const uiSingletonExternalRequest = resolveUiSingletonServerExternalRequest(request, resolveFromAppOrCore);
|
|
181
|
+
if (uiSingletonExternalRequest !== undefined) {
|
|
182
|
+
return callback(undefined, 'commonjs ' + uiSingletonExternalRequest);
|
|
183
|
+
}
|
|
184
|
+
|
|
163
185
|
const shouldCompile =
|
|
164
|
-
request !== undefined &&
|
|
165
186
|
// Local files
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
187
|
+
request[0] === '.' ||
|
|
188
|
+
request[0] === '/' ||
|
|
189
|
+
// Aliased modules
|
|
190
|
+
app.aliases.server.containsAlias(request) ||
|
|
191
|
+
// TODO: proteum.conf: compile: include
|
|
192
|
+
app.isTranspileModuleRequest(request) ||
|
|
193
|
+
// Compile proteum modules
|
|
194
|
+
request.startsWith('proteum') ||
|
|
195
|
+
// React/Preact singleton packages and React-based UI packages must pass through the alias layer on the server,
|
|
196
|
+
// otherwise SSR can mix real React packages with the Preact compat runtime.
|
|
197
|
+
isUiSingletonRequest(request) ||
|
|
198
|
+
serverReactCompatCompilePrefixes.some((prefix) => request.startsWith(prefix));
|
|
177
199
|
|
|
178
200
|
//console.log('isNodeModule', request, isNodeModule);
|
|
179
201
|
|
|
@@ -14,6 +14,7 @@ export const proteumCommandNames = [
|
|
|
14
14
|
'typecheck',
|
|
15
15
|
'lint',
|
|
16
16
|
'check',
|
|
17
|
+
'docs',
|
|
17
18
|
'e2e',
|
|
18
19
|
'connect',
|
|
19
20
|
'doctor',
|
|
@@ -301,6 +302,19 @@ export const proteumCommands: Record<TProteumCommandName, TProteumCommandDoc> =
|
|
|
301
302
|
notes: ['This command executes refresh, typecheck, then lint in that order.', 'From a monorepo wrapper root, check runs once per discovered Proteum app.'],
|
|
302
303
|
status: 'stable',
|
|
303
304
|
},
|
|
305
|
+
docs: {
|
|
306
|
+
name: 'docs',
|
|
307
|
+
category: 'Quality gates',
|
|
308
|
+
summary: 'Check that code and documentation still point at each other.',
|
|
309
|
+
usage: 'proteum docs check',
|
|
310
|
+
bestFor: 'Confirming doc anchors resolve and that fix notes and feature packs are reachable from code.',
|
|
311
|
+
examples: [{ description: 'Check every doc anchor in the repository', command: 'proteum docs check' }],
|
|
312
|
+
notes: [
|
|
313
|
+
'Only an anchor that no longer resolves fails the command; missing coverage is reported as a backlog.',
|
|
314
|
+
'Anchors are the `@docs`, `@adr`, `@fix`, and `@rule` tags described in `CODING_STYLE.md`.',
|
|
315
|
+
],
|
|
316
|
+
status: 'stable',
|
|
317
|
+
},
|
|
304
318
|
e2e: {
|
|
305
319
|
name: 'e2e',
|
|
306
320
|
category: 'Quality gates',
|
|
@@ -594,7 +608,7 @@ export const proteumCommands: Record<TProteumCommandName, TProteumCommandDoc> =
|
|
|
594
608
|
name: 'session',
|
|
595
609
|
category: 'Manifest and contracts',
|
|
596
610
|
summary: 'Mint a dev-only auth session token and cookie payload for a known user.',
|
|
597
|
-
usage: 'proteum session <email> [--role <role>] [--port <port>|--url <baseUrl>] [--json]',
|
|
611
|
+
usage: 'proteum session <email> [--role <role>] [--redirect <path>] [--port <port>|--url <baseUrl>] [--json]',
|
|
598
612
|
bestFor:
|
|
599
613
|
'Starting browser or API automation from an authenticated state without driving the login UI, while still using the app-configured auth service.',
|
|
600
614
|
examples: [
|
|
@@ -606,11 +620,16 @@ export const proteumCommands: Record<TProteumCommandName, TProteumCommandDoc> =
|
|
|
606
620
|
description: 'Mint a GOD session for unique.domains and print machine-readable cookie data',
|
|
607
621
|
command: 'proteum session god@example.com --role GOD --json',
|
|
608
622
|
},
|
|
623
|
+
{
|
|
624
|
+
description: 'Print a browser login URL that sets the cookie and opens a protected page',
|
|
625
|
+
command: 'proteum session admin@example.com --port 3101 --redirect /admin --json',
|
|
626
|
+
},
|
|
609
627
|
],
|
|
610
628
|
notes: [
|
|
611
629
|
'Sessions are available only in dev mode and use the auth service registered on the current app router.',
|
|
612
630
|
'You must provide the target user email explicitly; Proteum does not guess your admin account universally across apps.',
|
|
613
631
|
'The command returns a token plus Playwright-ready cookie JSON so agents can inject the session into a browser context directly.',
|
|
632
|
+
'The command also returns a browser login URL that works on localhost dev servers, sets the same session cookie, and redirects to a local path.',
|
|
614
633
|
'Without `--port` or `--url`, Proteum refreshes generated artifacts, builds the dev output, starts a temporary local dev server, creates the session, prints the payload, and exits.',
|
|
615
634
|
],
|
|
616
635
|
status: 'experimental',
|
package/cli/runtime/commands.ts
CHANGED
|
@@ -352,6 +352,22 @@ class CheckCommand extends ProteumCommand {
|
|
|
352
352
|
}
|
|
353
353
|
}
|
|
354
354
|
|
|
355
|
+
class DocsCommand extends ProteumCommand {
|
|
356
|
+
public static paths = [['docs']];
|
|
357
|
+
|
|
358
|
+
public static usage = buildUsage('docs');
|
|
359
|
+
|
|
360
|
+
public args = Option.Rest();
|
|
361
|
+
|
|
362
|
+
public async execute() {
|
|
363
|
+
const [action = '', ...restArgs] = this.args;
|
|
364
|
+
|
|
365
|
+
assertNoLegacyArgs('docs', restArgs);
|
|
366
|
+
this.setCliArgs({ action });
|
|
367
|
+
await runCommandModule(() => import('../commands/docs'));
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
355
371
|
class E2eCommand extends ProteumCommand {
|
|
356
372
|
public static paths = [['e2e']];
|
|
357
373
|
|
|
@@ -617,6 +633,7 @@ class SessionCommand extends ProteumCommand {
|
|
|
617
633
|
public role = Option.String('--role', { description: 'Require the resolved user to have the given role.' });
|
|
618
634
|
public port = Option.String('--port', { description: 'Target an existing dev server on the given port.' });
|
|
619
635
|
public url = Option.String('--url', { description: 'Target an existing dev server at the given base URL.' });
|
|
636
|
+
public redirect = Option.String('--redirect', { description: 'Local path used by the browser login URL.' });
|
|
620
637
|
public json = Option.Boolean('--json', false, { description: 'Print JSON output.' });
|
|
621
638
|
public args = Option.Rest();
|
|
622
639
|
|
|
@@ -628,6 +645,7 @@ class SessionCommand extends ProteumCommand {
|
|
|
628
645
|
role: this.role ?? '',
|
|
629
646
|
port: this.port ?? '',
|
|
630
647
|
url: this.url ?? '',
|
|
648
|
+
redirect: this.redirect ?? '',
|
|
631
649
|
json: this.json,
|
|
632
650
|
});
|
|
633
651
|
|
|
@@ -917,6 +935,7 @@ export const registeredCommands = {
|
|
|
917
935
|
typecheck: TypecheckCommand,
|
|
918
936
|
lint: LintCommand,
|
|
919
937
|
check: CheckCommand,
|
|
938
|
+
docs: DocsCommand,
|
|
920
939
|
e2e: E2eCommand,
|
|
921
940
|
connect: ConnectCommand,
|
|
922
941
|
doctor: DoctorCommand,
|
|
@@ -953,6 +972,7 @@ export const createCli = (version: string) => {
|
|
|
953
972
|
clipanion.register(TypecheckCommand);
|
|
954
973
|
clipanion.register(LintCommand);
|
|
955
974
|
clipanion.register(CheckCommand);
|
|
975
|
+
clipanion.register(DocsCommand);
|
|
956
976
|
clipanion.register(E2eCommand);
|
|
957
977
|
clipanion.register(ConnectCommand);
|
|
958
978
|
clipanion.register(DoctorCommand);
|
package/cli/scaffold/index.ts
CHANGED
|
@@ -556,6 +556,9 @@ export const runCreateScaffold = async () => {
|
|
|
556
556
|
|
|
557
557
|
result.notes.push(...plan.notes);
|
|
558
558
|
result.nextSteps.push(...plan.nextSteps);
|
|
559
|
+
result.nextSteps.push(
|
|
560
|
+
'Adapt the generated code to the real feature and record non-obvious decisions as why-comments per `CODING_STYLE.md` (`Decision and context comments`).',
|
|
561
|
+
);
|
|
559
562
|
printResult(result);
|
|
560
563
|
};
|
|
561
564
|
|
|
@@ -22,7 +22,15 @@ export const createPageTemplate = ({
|
|
|
22
22
|
routePath: string;
|
|
23
23
|
heading: string;
|
|
24
24
|
message: string;
|
|
25
|
-
}) =>
|
|
25
|
+
}) => `/*----------------------------------
|
|
26
|
+
- DEPENDANCES
|
|
27
|
+
----------------------------------*/
|
|
28
|
+
|
|
29
|
+
import { definePageRoute } from '@common/router/definitions';
|
|
30
|
+
|
|
31
|
+
/*----------------------------------
|
|
32
|
+
- PAGE
|
|
33
|
+
----------------------------------*/
|
|
26
34
|
|
|
27
35
|
export default definePageRoute({
|
|
28
36
|
path: ${JSON.stringify(routePath)},
|
|
@@ -53,7 +61,15 @@ export const createControllerTemplate = ({
|
|
|
53
61
|
appIdentifier: string;
|
|
54
62
|
className: string;
|
|
55
63
|
methodName: string;
|
|
56
|
-
}) =>
|
|
64
|
+
}) => `/*----------------------------------
|
|
65
|
+
- DEPENDANCES
|
|
66
|
+
----------------------------------*/
|
|
67
|
+
|
|
68
|
+
import { defineAction, defineController } from '@generated/server/controller';
|
|
69
|
+
|
|
70
|
+
/*----------------------------------
|
|
71
|
+
- CONTROLEUR
|
|
72
|
+
----------------------------------*/
|
|
57
73
|
|
|
58
74
|
export default defineController({
|
|
59
75
|
actions: {
|
|
@@ -74,11 +90,23 @@ export const createCommandTemplate = ({
|
|
|
74
90
|
}: {
|
|
75
91
|
className: string;
|
|
76
92
|
methodName: string;
|
|
77
|
-
}) =>
|
|
93
|
+
}) => `/*----------------------------------
|
|
94
|
+
- DEPENDANCES
|
|
95
|
+
----------------------------------*/
|
|
96
|
+
|
|
97
|
+
import { Commands } from '@server/app/commands';
|
|
78
98
|
import type AppApplication from '@/server/index';
|
|
79
99
|
|
|
100
|
+
/*----------------------------------
|
|
101
|
+
- TYPES
|
|
102
|
+
----------------------------------*/
|
|
103
|
+
|
|
80
104
|
type App = InstanceType<typeof AppApplication>;
|
|
81
105
|
|
|
106
|
+
/*----------------------------------
|
|
107
|
+
- COMMANDS
|
|
108
|
+
----------------------------------*/
|
|
109
|
+
|
|
82
110
|
export default class ${className} extends Commands<App> {
|
|
83
111
|
public async ${methodName}() {
|
|
84
112
|
return {
|
|
@@ -95,7 +123,15 @@ export const createRouteTemplate = ({
|
|
|
95
123
|
}: {
|
|
96
124
|
httpMethod: string;
|
|
97
125
|
routePath: string;
|
|
98
|
-
}) =>
|
|
126
|
+
}) => `/*----------------------------------
|
|
127
|
+
- DEPENDANCES
|
|
128
|
+
----------------------------------*/
|
|
129
|
+
|
|
130
|
+
import { defineServerRoute } from '@common/router/definitions';
|
|
131
|
+
|
|
132
|
+
/*----------------------------------
|
|
133
|
+
- ROUTES
|
|
134
|
+
----------------------------------*/
|
|
99
135
|
|
|
100
136
|
export default defineServerRoute({
|
|
101
137
|
method: ${JSON.stringify(httpMethod.toUpperCase())},
|
|
@@ -115,12 +151,24 @@ export const createServiceTemplate = ({
|
|
|
115
151
|
}: {
|
|
116
152
|
appIdentifier: string;
|
|
117
153
|
className: string;
|
|
118
|
-
}) =>
|
|
154
|
+
}) => `/*----------------------------------
|
|
155
|
+
- DEPENDANCES
|
|
156
|
+
----------------------------------*/
|
|
157
|
+
|
|
158
|
+
import Service from '@server/app/service';
|
|
159
|
+
|
|
160
|
+
/*----------------------------------
|
|
161
|
+
- TYPES
|
|
162
|
+
----------------------------------*/
|
|
119
163
|
|
|
120
164
|
export type Config = {
|
|
121
165
|
debug?: boolean;
|
|
122
166
|
};
|
|
123
167
|
|
|
168
|
+
/*----------------------------------
|
|
169
|
+
- SERVICE
|
|
170
|
+
----------------------------------*/
|
|
171
|
+
|
|
124
172
|
export default class ${className} extends Service<Config, {}, ${appIdentifier}, ${appIdentifier}> {
|
|
125
173
|
public async health() {
|
|
126
174
|
return {
|
|
@@ -138,9 +186,17 @@ export const createServiceConfigTemplate = ({
|
|
|
138
186
|
configExportName: string;
|
|
139
187
|
serviceImportPath: string;
|
|
140
188
|
serviceImportName: string;
|
|
141
|
-
}) =>
|
|
189
|
+
}) => `/*----------------------------------
|
|
190
|
+
- DEPENDANCES
|
|
191
|
+
----------------------------------*/
|
|
192
|
+
|
|
193
|
+
import { Services } from '@server/app';
|
|
142
194
|
import ${serviceImportName} from ${JSON.stringify(serviceImportPath)};
|
|
143
195
|
|
|
196
|
+
/*----------------------------------
|
|
197
|
+
- CONFIG
|
|
198
|
+
----------------------------------*/
|
|
199
|
+
|
|
144
200
|
export const ${configExportName} = Services.config(${serviceImportName}, {});
|
|
145
201
|
`;
|
|
146
202
|
|
package/cli/utils/agents.ts
CHANGED
|
@@ -1053,11 +1053,11 @@ function renderEmbeddedProjectInstructions({
|
|
|
1053
1053
|
'- Worktree Preflight (`cwd` inside `/.codex/worktrees/`, newly created Proteum worktree, or before editing in a Codex worktree): read Root contract fallback, run `npx proteum worktree init --source <source-app-root>` when the bootstrap marker is missing, run `npx proteum worktree init --source <source-app-root> --refresh` when Proteum reports stale bootstrap state, use `--skip-deps --reason "..."` only for intentional dependency skips, then run `npx proteum runtime status`; for runtime-visible work start or reuse one tracked `npx proteum dev` session using the Task Lifecycle launch workflow.',
|
|
1054
1054
|
'- Git lifecycle (`commit`, `and commit`, `stage`, `push`, `PR`, pull request): read Root contract fallback before any git write.',
|
|
1055
1055
|
'- Before git writes after a bug fix, behavior change, decision change, or docs-relevant production change: read `DOCUMENTATION.md` and verify required docs, fix notes, or ADRs were updated or explicitly skipped with a reason.',
|
|
1056
|
-
'- Before finishing production code changes: read Root contract fallback, `DOCUMENTATION.md`, `CODING_STYLE.md`, `tests/AGENTS.md`, and any touched area `AGENTS.md`.',
|
|
1056
|
+
'- Before finishing production code changes: read Root contract fallback, `DOCUMENTATION.md`, `CODING_STYLE.md`, `tests/AGENTS.md`, and any touched area `AGENTS.md`. Run the `CODING_STYLE.md` self-check on the final diff; a non-obvious decision, workaround, or bug fix without a why-comment is a defect to fix before finishing.',
|
|
1057
1057
|
'- Runtime-visible, request-time, router, SSR, browser, or controller behavior: read Root contract fallback and `diagnostics.md` for verification routing.',
|
|
1058
1058
|
'- Bug fixes, regressions, incidents, broken public routes, auth/OAuth failures, integration failures, or production behavior fixes: read `DOCUMENTATION.md` before editing and update the relevant fix/regression docs when required.',
|
|
1059
1059
|
'- Non-trivial feature, product, business-rule, UX, copy, or docs changes: read `DOCUMENTATION.md` before editing.',
|
|
1060
|
-
'- Implementation edits: read `CODING_STYLE.md` before editing, plus the matching area file from the routing table.',
|
|
1060
|
+
'- Implementation edits: read `CODING_STYLE.md` before editing, plus the matching area file from the routing table. While editing, record non-obvious decisions, workarounds, and constraints as why-comments per its `Decision and context comments` section.',
|
|
1061
1061
|
'',
|
|
1062
1062
|
'## Routing Table',
|
|
1063
1063
|
'',
|
|
@@ -144,6 +144,13 @@ const isDocsOnlyFile = (filepath: string) =>
|
|
|
144
144
|
filepath.startsWith('agents/') ||
|
|
145
145
|
docsOnlyExtensions.has(path.extname(filepath));
|
|
146
146
|
|
|
147
|
+
/**
|
|
148
|
+
* A change that can break the code-to-documentation link: either the corpus
|
|
149
|
+
* moved under the anchors, or a source file that may carry anchors changed.
|
|
150
|
+
*/
|
|
151
|
+
const isDocAnchorRelevantFile = (filepath: string) =>
|
|
152
|
+
filepath.startsWith('docs/') || isRelatedSourceFile(filepath);
|
|
153
|
+
|
|
147
154
|
const normalizeGlob = (glob: string) => normalizePath(glob.trim());
|
|
148
155
|
|
|
149
156
|
const escapeRegExp = (value: string) => value.replace(/[|\\{}()[\]^$+?.]/g, '\\$&');
|
|
@@ -350,6 +357,20 @@ export const buildChangedVerificationPlan = ({
|
|
|
350
357
|
if (check) addCheck({ check, selectedChecks });
|
|
351
358
|
}
|
|
352
359
|
|
|
360
|
+
const docAnchorFiles = files.filter(isDocAnchorRelevantFile);
|
|
361
|
+
if (docAnchorFiles.length > 0) {
|
|
362
|
+
const check = createSuiteCheck({
|
|
363
|
+
configRoot: gitRoot,
|
|
364
|
+
files: docAnchorFiles,
|
|
365
|
+
id: 'builtin:doc-anchors',
|
|
366
|
+
reason: 'Changed docs or source files should keep doc anchors resolvable.',
|
|
367
|
+
scope: 'static',
|
|
368
|
+
source: 'builtin',
|
|
369
|
+
suite: 'npx proteum docs check',
|
|
370
|
+
});
|
|
371
|
+
if (check) addCheck({ check, selectedChecks });
|
|
372
|
+
}
|
|
373
|
+
|
|
353
374
|
for (const rule of config.rules || []) {
|
|
354
375
|
const matchedFiles = matchFiles(files, rule.match);
|
|
355
376
|
if (matchedFiles.length === 0) continue;
|