@jmruthers/pace-core 0.6.6 → 0.6.8
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/{scripts/audit/audit-dependencies.cjs → audit-tool/00-dependencies.cjs} +227 -22
- package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
- package/audit-tool/audits/02-project-structure.cjs +240 -0
- package/audit-tool/audits/03-architecture.cjs +224 -0
- package/audit-tool/audits/04-code-quality.cjs +149 -0
- package/audit-tool/audits/05-styling.cjs +224 -0
- package/audit-tool/audits/06-security-rbac.cjs +554 -0
- package/audit-tool/audits/07-api-tech-stack.cjs +355 -0
- package/audit-tool/audits/08-testing-documentation.cjs +202 -0
- package/audit-tool/audits/09-operations.cjs +208 -0
- package/audit-tool/index.cjs +295 -0
- package/audit-tool/utils/code-utils.cjs +218 -0
- package/audit-tool/utils/file-utils.cjs +230 -0
- package/audit-tool/utils/report-utils.cjs +380 -0
- package/cursor-rules/00-standards-overview.mdc +156 -0
- package/cursor-rules/{00-pace-core-compliance.mdc → 01-pace-core-compliance.mdc} +187 -34
- package/cursor-rules/02-project-structure.mdc +37 -5
- package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +125 -11
- package/cursor-rules/04-code-quality.mdc +419 -0
- package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +55 -10
- package/cursor-rules/{09-rbac-compliance.mdc → 06-security-rbac.mdc} +62 -6
- package/cursor-rules/07-api-tech-stack.mdc +377 -0
- package/cursor-rules/08-testing-documentation.mdc +324 -0
- package/cursor-rules/09-operations.mdc +365 -0
- package/dist/DataTable-6RMSCQJ6.js +15 -0
- package/dist/{DataTable-2N_tqbfq.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
- package/dist/{PublicPageProvider-BBH6Vqg7.d.ts → PublicPageProvider-CIGSujI2.d.ts} +40 -24
- package/dist/{UnifiedAuthProvider-ZT6TIGM7.js → UnifiedAuthProvider-7SNDOWYD.js} +2 -2
- package/dist/{api-Y4MQWOFW.js → api-7P7DI652.js} +1 -1
- package/dist/{chunk-MAGBIDNS.js → chunk-4DDCYDQ3.js} +8 -7
- package/dist/{chunk-BVP2BCJF.js → chunk-5W2A3DRC.js} +10 -9
- package/dist/{chunk-SD6WQY43.js → chunk-7ILTDCL2.js} +9 -1
- package/dist/{chunk-3QC3KRHK.js → chunk-A3W6LW53.js} +16 -1
- package/dist/{chunk-3O3WHILE.js → chunk-EF2UGZWY.js} +239 -63
- package/dist/{chunk-LAZMKTTF.js → chunk-EURB7QFZ.js} +341 -337
- package/dist/{chunk-2HGJFNAH.js → chunk-FEJLJNWA.js} +1 -15
- package/dist/{chunk-7TYHROIV.js → chunk-GS5672WG.js} +55 -13
- package/dist/{chunk-UIYSCEV7.js → chunk-IUBRCBSY.js} +1 -1
- package/dist/{chunk-ZFYPMX46.js → chunk-LX6U42O3.js} +1 -1
- package/dist/{chunk-FENMYN2U.js → chunk-MPBLMWVR.js} +3 -3
- package/dist/{chunk-ZS5VO5JB.js → chunk-NKHKXPI4.js} +408 -453
- package/dist/{chunk-A55DK444.js → chunk-OJ4SKRSV.js} +1 -7
- package/dist/{chunk-4T7OBVTU.js → chunk-S6ZQKDY6.js} +1 -1
- package/dist/{chunk-FTCRZOG2.js → chunk-T5CVK4R3.js} +5 -5
- package/dist/{chunk-OHIK3MIO.js → chunk-Z2FNRKF3.js} +13 -13
- package/dist/components.d.ts +5 -4
- package/dist/components.js +29 -34
- package/dist/eslint-rules/index.cjs +22 -9
- package/{src/eslint-rules/rules/compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +184 -23
- package/dist/eslint-rules/rules/04-code-quality.cjs +346 -0
- package/dist/eslint-rules/rules/05-styling.cjs +61 -0
- package/dist/eslint-rules/rules/{rbac.cjs → 06-security-rbac.cjs} +34 -13
- package/dist/eslint-rules/rules/07-api-tech-stack.cjs +385 -0
- package/dist/eslint-rules/rules/08-testing.cjs +94 -0
- package/dist/{functions-DHebl8-F.d.ts → functions-lBy5L2ry.d.ts} +1 -1
- package/dist/hooks.d.ts +5 -5
- package/dist/hooks.js +8 -8
- package/dist/index.d.ts +7 -7
- package/dist/index.js +21 -20
- package/dist/providers.js +2 -2
- package/dist/rbac/index.d.ts +1 -1
- package/dist/rbac/index.js +8 -8
- package/dist/theming/runtime.d.ts +61 -1
- package/dist/theming/runtime.js +1 -1
- package/dist/{types-B-K_5VnO.d.ts → types-DXstZpNI.d.ts} +0 -17
- package/dist/types.d.ts +2 -2
- package/dist/{usePublicRouteParams-COZ28Mvq.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +19 -19
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +8 -8
- package/docs/README.md +1 -1
- package/docs/api/modules.md +106 -41
- package/docs/api-reference/components.md +18 -20
- package/docs/api-reference/hooks.md +80 -80
- package/docs/api-reference/types.md +1 -1
- package/docs/api-reference/utilities.md +1 -1
- package/docs/architecture/README.md +1 -1
- package/docs/core-concepts/events.md +3 -3
- package/docs/core-concepts/organisations.md +6 -6
- package/docs/core-concepts/permissions.md +6 -6
- package/docs/documentation-index.md +12 -18
- package/docs/getting-started/dependencies.md +23 -0
- package/docs/getting-started/documentation-index.md +1 -1
- package/docs/getting-started/examples/README.md +4 -4
- package/docs/getting-started/examples/full-featured-app.md +1 -1
- package/docs/getting-started/faq.md +2 -2
- package/docs/getting-started/quick-reference.md +4 -4
- package/docs/implementation-guides/app-layout.md +1 -1
- package/docs/implementation-guides/authentication.md +15 -15
- package/docs/implementation-guides/component-styling.md +1 -1
- package/docs/implementation-guides/data-tables.md +127 -34
- package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
- package/docs/implementation-guides/dynamic-colors.md +3 -3
- package/docs/implementation-guides/file-upload-storage.md +2 -2
- package/docs/implementation-guides/hierarchical-datatable.md +40 -60
- package/docs/implementation-guides/inactivity-tracking.md +3 -3
- package/docs/implementation-guides/large-datasets.md +3 -2
- package/docs/implementation-guides/organisation-security.md +2 -2
- package/docs/implementation-guides/performance.md +2 -2
- package/docs/implementation-guides/permission-enforcement.md +1 -1
- package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
- package/docs/migration/V0.4.0_rbac-migration.md +6 -6
- package/docs/rbac/README.md +5 -5
- package/docs/rbac/advanced-patterns.md +6 -6
- package/docs/rbac/api-reference.md +20 -20
- package/docs/rbac/event-based-apps.md +3 -3
- package/docs/rbac/examples.md +41 -41
- package/docs/rbac/getting-started.md +37 -37
- package/docs/rbac/performance.md +1 -1
- package/docs/rbac/quick-start.md +52 -52
- package/docs/rbac/secure-client-protection.md +1 -1
- package/docs/rbac/troubleshooting.md +1 -1
- package/docs/security/README.md +5 -5
- package/docs/standards/0-standards-overview.md +220 -0
- package/docs/standards/{00-pace-core-compliance.md → 1-pace-core-compliance-standards.md} +241 -185
- package/docs/standards/{02-project-structure.md → 2-project-structure-standards.md} +11 -47
- package/docs/standards/3-architecture-standards.md +606 -0
- package/docs/standards/4-code-quality-standards.md +728 -0
- package/docs/standards/{08-markup-quality.md → 5-styling-standards.md} +12 -9
- package/docs/standards/{09-rbac-compliance.md → 6-security-rbac-standards.md} +126 -18
- package/docs/standards/7-api-tech-stack-standards.md +662 -0
- package/docs/standards/8-testing-documentation-standards.md +401 -0
- package/docs/standards/9-operations-standards.md +1102 -0
- package/docs/standards/README.md +203 -104
- package/docs/troubleshooting/README.md +4 -4
- package/docs/troubleshooting/common-issues.md +2 -2
- package/docs/troubleshooting/debugging.md +9 -9
- package/docs/troubleshooting/migration.md +4 -4
- package/eslint-config-pace-core.cjs +50 -20
- package/package.json +50 -19
- package/scripts/eslint-audit.cjs +123 -0
- package/scripts/install-cursor-rules.cjs +11 -243
- package/scripts/install-eslint-config.cjs +349 -0
- package/scripts/validate-dependencies.cjs +248 -0
- package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +2 -2
- package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
- package/src/__tests__/helpers/__tests__/test-utils.test.tsx +30 -18
- package/src/__tests__/integration/UserProfile.test.tsx +14 -14
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
- package/src/__tests__/templates/accessibility.test.template.tsx +10 -9
- package/src/__tests__/templates/component.test.template.tsx +18 -15
- package/src/components/AddressField/AddressField.tsx +26 -1
- package/src/components/Alert/Alert.test.tsx +86 -22
- package/src/components/Alert/Alert.tsx +19 -11
- package/src/components/Badge/Badge.tsx +1 -1
- package/src/components/Calendar/Calendar.tsx +201 -47
- package/src/components/Checkbox/Checkbox.test.tsx +2 -1
- package/src/components/ContextSelector/ContextSelector.tsx +108 -126
- package/src/components/DataTable/AUDIT_REPORT.md +293 -0
- package/src/components/DataTable/DataTable.tsx +1 -19
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +6 -2
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +21 -6
- package/src/components/DataTable/__tests__/pagination.modes.test.tsx +3 -2
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
- package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
- package/src/components/DataTable/components/DataTableLayout.tsx +5 -16
- package/src/components/DataTable/components/EditableRow.tsx +5 -7
- package/src/components/DataTable/components/EmptyState.tsx +11 -10
- package/src/components/DataTable/components/FilterRow.tsx +2 -4
- package/src/components/DataTable/components/ImportModal.tsx +124 -126
- package/src/components/DataTable/components/LoadingState.tsx +5 -6
- package/src/components/DataTable/components/SortIndicator.tsx +50 -0
- package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
- package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
- package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
- package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +45 -27
- package/src/components/DataTable/components/index.ts +2 -1
- package/src/components/DataTable/types.ts +0 -18
- package/src/components/DataTable/utils/a11yUtils.ts +17 -0
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +1 -1
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
- package/src/components/DateTimeField/DateTimeField.tsx +7 -8
- package/src/components/Dialog/Dialog.test.tsx +1 -0
- package/src/components/Dialog/Dialog.tsx +25 -8
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
- package/src/components/FileUpload/FileUpload.test.tsx +45 -16
- package/src/components/FileUpload/FileUpload.tsx +141 -130
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +48 -12
- package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +9 -9
- package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +30 -30
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +4 -4
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +7 -1
- package/src/components/Progress/Progress.tsx +2 -4
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
- package/src/components/Select/Select.tsx +86 -77
- package/src/components/Select/types.ts +3 -0
- package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
- package/src/hooks/__tests__/hooks.integration.test.tsx +49 -49
- package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +8 -5
- package/src/hooks/__tests__/useFileUrl.unit.test.ts +4 -0
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +99 -99
- package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +45 -8
- package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +22 -2
- package/src/hooks/public/usePublicEvent.ts +5 -5
- package/src/hooks/public/usePublicEventLogo.ts +5 -5
- package/src/hooks/public/usePublicFileDisplay.ts +2 -2
- package/src/hooks/public/usePublicRouteParams.ts +13 -9
- package/src/hooks/useAddressAutocomplete.test.ts +18 -18
- package/src/hooks/useAppConfig.ts +2 -2
- package/src/hooks/useEventTheme.test.ts +7 -7
- package/src/hooks/useEventTheme.ts +2 -1
- package/src/hooks/useFileDisplay.ts +2 -2
- package/src/hooks/useFileUrl.ts +52 -8
- package/src/hooks/useOrganisationSecurity.test.ts +2 -1
- package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
- package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
- package/src/providers/__tests__/EventProvider.test.tsx +61 -61
- package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
- package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
- package/src/providers/__tests__/ProviderLifecycle.test.tsx +38 -38
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +10 -10
- package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +15 -6
- package/src/rbac/__tests__/rbac-functions.test.ts +3 -3
- package/src/rbac/api.test.ts +104 -0
- package/src/rbac/engine.ts +1 -1
- package/src/rbac/hooks/useCan.test.ts +2 -2
- package/src/rbac/secureClient.ts +1 -1
- package/src/rbac/types/functions.ts +1 -1
- package/src/styles/core.css +7 -0
- package/src/theming/__tests__/parseEventColours.test.ts +118 -3
- package/src/theming/parseEventColours.ts +77 -11
- package/src/types/supabase.ts +2 -3
- package/src/utils/__tests__/bundleAnalysis.unit.test.ts +9 -9
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
- package/src/utils/file-reference/__tests__/file-reference.test.ts +4 -0
- package/src/utils/formatting/formatDate.test.ts +3 -2
- package/src/utils/formatting/formatDateTime.test.ts +2 -2
- package/src/utils/google-places/googlePlacesUtils.test.ts +36 -24
- package/src/utils/storage/README.md +1 -1
- package/src/utils/storage/__tests__/helpers.unit.test.ts +19 -12
- package/src/utils/storage/helpers.test.ts +69 -3
- package/cursor-rules/01-standards-compliance.mdc +0 -285
- package/cursor-rules/04-testing-standards.mdc +0 -270
- package/cursor-rules/05-bug-reports-and-features.mdc +0 -248
- package/cursor-rules/06-code-quality.mdc +0 -311
- package/cursor-rules/07-tech-stack-compliance.mdc +0 -216
- package/cursor-rules/10-error-handling-patterns.mdc +0 -179
- package/cursor-rules/11-performance-optimization.mdc +0 -169
- package/cursor-rules/12-ci-cd-integration.mdc +0 -150
- package/dist/DataTable-LRJL4IRV.js +0 -15
- package/dist/eslint-rules/rules/compliance.cjs +0 -348
- package/dist/eslint-rules/rules/components.cjs +0 -113
- package/dist/eslint-rules/rules/imports.cjs +0 -102
- package/docs/best-practices/README.md +0 -472
- package/docs/best-practices/accessibility.md +0 -604
- package/docs/best-practices/common-patterns.md +0 -516
- package/docs/best-practices/deployment.md +0 -1103
- package/docs/best-practices/performance.md +0 -1328
- package/docs/best-practices/security.md +0 -940
- package/docs/best-practices/testing.md +0 -1034
- package/docs/rbac/compliance/compliance-guide.md +0 -544
- package/docs/standards/01-standards-compliance.md +0 -188
- package/docs/standards/03-solid-principles.md +0 -39
- package/docs/standards/04-testing-standards.md +0 -36
- package/docs/standards/05-bug-reports-and-features.md +0 -27
- package/docs/standards/06-code-quality.md +0 -34
- package/docs/standards/07-tech-stack-compliance.md +0 -30
- package/docs/standards/10-error-handling-patterns.md +0 -401
- package/docs/standards/11-performance-optimization.md +0 -348
- package/docs/standards/12-ci-cd-integration.md +0 -370
- package/docs/standards/ALIGNMENT_REVIEW_SUMMARY.md +0 -192
- package/scripts/audit/audit-compliance.cjs +0 -1295
- package/scripts/audit/audit-components.cjs +0 -260
- package/scripts/audit/audit-rbac.cjs +0 -954
- package/scripts/audit/audit-standards.cjs +0 -1268
- package/scripts/audit/index.cjs +0 -1927
- package/src/components/DataTable/components/DataTableBody.tsx +0 -478
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
- package/src/components/DataTable/components/ExpandButton.tsx +0 -113
- package/src/components/DataTable/components/GroupHeader.tsx +0 -54
- package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
- package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
- package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
- package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
- package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
- package/src/components/DataTable/core/DataTableContext.tsx +0 -216
- package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
- package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
- package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
- package/src/components/DataTable/utils/debugTools.ts +0 -514
- package/src/eslint-rules/index.cjs +0 -22
- package/src/eslint-rules/rules/components.cjs +0 -113
- package/src/eslint-rules/rules/imports.cjs +0 -102
- package/src/eslint-rules/rules/rbac.cjs +0 -790
- package/src/eslint-rules/utils/helpers.cjs +0 -42
- package/src/eslint-rules/utils/manifest-loader.cjs +0 -75
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard 7: API & Tech Stack Audit
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module Audit/Standard7
|
|
5
|
+
*
|
|
6
|
+
* Audits consuming apps for compliance with Standard 7: API & Tech Stack.
|
|
7
|
+
* Validates RPC naming in SQL migrations, tech stack versions, and Vite configuration.
|
|
8
|
+
*
|
|
9
|
+
* Reference: packages/core/docs/standards/7-api-tech-stack-standards.md
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const { findSQLFiles, findConfigFiles, readFileSafe, getRelativePath, findPaceCorePackageJson } = require('../utils/file-utils.cjs');
|
|
15
|
+
const { getLineNumber, getCodeSnippet, isInCommentOrStringSQL } = require('../utils/code-utils.cjs');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Check RPC naming in SQL migrations (data_* for reads, app_* for writes)
|
|
19
|
+
*/
|
|
20
|
+
function checkRPCNaming(consumingAppPath) {
|
|
21
|
+
const issues = [];
|
|
22
|
+
|
|
23
|
+
// Find SQL migration files
|
|
24
|
+
const migrationsPath = path.join(consumingAppPath, 'supabase', 'migrations');
|
|
25
|
+
const altMigrationsPath = path.join(consumingAppPath, 'migrations');
|
|
26
|
+
|
|
27
|
+
const migrationsDir = fs.existsSync(migrationsPath) ? migrationsPath :
|
|
28
|
+
(fs.existsSync(altMigrationsPath) ? altMigrationsPath : null);
|
|
29
|
+
|
|
30
|
+
if (!migrationsDir) {
|
|
31
|
+
return issues; // No migrations directory, skip check
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const sqlFiles = findSQLFiles(migrationsDir);
|
|
35
|
+
|
|
36
|
+
sqlFiles.forEach(filePath => {
|
|
37
|
+
try {
|
|
38
|
+
const content = readFileSafe(filePath);
|
|
39
|
+
if (!content) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const relativePath = getRelativePath(filePath, consumingAppPath);
|
|
44
|
+
|
|
45
|
+
// Find CREATE FUNCTION statements for RPCs
|
|
46
|
+
const functionPattern = /CREATE\s+(?:OR\s+REPLACE\s+)?FUNCTION\s+(?:public\.)?["']?([^"'\s()]+)["']?\s*\(/gi;
|
|
47
|
+
let match;
|
|
48
|
+
|
|
49
|
+
while ((match = functionPattern.exec(content)) !== null) {
|
|
50
|
+
const functionName = match[1];
|
|
51
|
+
const functionStart = match.index;
|
|
52
|
+
|
|
53
|
+
if (isInCommentOrStringSQL(content, functionStart)) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Skip if it's a helper function (starts with check_, get_, is_)
|
|
58
|
+
if (/^(check_|get_|is_)/i.test(functionName)) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Check if it's a system function (starts with pg_ or other system prefixes)
|
|
63
|
+
if (/^(pg_|information_schema|current_|session_|set_|reset_|show_)/i.test(functionName)) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Check if it's an RPC (functions that are exposed as RPCs typically follow naming pattern)
|
|
68
|
+
// Skip if it's a helper function (doesn't follow data_* or app_* pattern)
|
|
69
|
+
if (!/^(data_|app_)/.test(functionName)) {
|
|
70
|
+
// Not an RPC, but should follow naming convention
|
|
71
|
+
issues.push({
|
|
72
|
+
type: 'rpcNaming',
|
|
73
|
+
file: relativePath,
|
|
74
|
+
line: getLineNumber(content, functionStart),
|
|
75
|
+
message: `RPC function '${functionName}' does not follow naming convention. Should start with 'data_' (read) or 'app_' (write) prefix.`,
|
|
76
|
+
code: getCodeSnippet(content, functionStart, 0, 100),
|
|
77
|
+
severity: 'error',
|
|
78
|
+
fix: `Rename function to follow pattern: data_${functionName} (for read) or app_${functionName} (for write)`,
|
|
79
|
+
});
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Check naming pattern: data_* for reads, app_* for writes
|
|
84
|
+
const readVerbs = ['list', 'get', 'read'];
|
|
85
|
+
const writeVerbs = ['create', 'update', 'delete', 'bulk_create', 'bulk_update'];
|
|
86
|
+
const validVerbs = [...readVerbs, ...writeVerbs];
|
|
87
|
+
|
|
88
|
+
const parts = functionName.split('_');
|
|
89
|
+
const verb = parts[parts.length - 1];
|
|
90
|
+
|
|
91
|
+
if (!validVerbs.includes(verb)) {
|
|
92
|
+
issues.push({
|
|
93
|
+
type: 'rpcNaming',
|
|
94
|
+
file: relativePath,
|
|
95
|
+
line: getLineNumber(content, functionStart),
|
|
96
|
+
message: `RPC '${functionName}' uses invalid verb '${verb}'. Use only: ${validVerbs.join(', ')}`,
|
|
97
|
+
code: getCodeSnippet(content, functionStart, 0, 100),
|
|
98
|
+
severity: 'error',
|
|
99
|
+
fix: `Rename RPC to use valid verb: ${functionName.replace(verb, validVerbs[0])}`,
|
|
100
|
+
});
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Check prefix-verb alignment
|
|
105
|
+
const hasDataPrefix = functionName.startsWith('data_');
|
|
106
|
+
const hasAppPrefix = functionName.startsWith('app_');
|
|
107
|
+
const isReadOperation = readVerbs.includes(verb);
|
|
108
|
+
const isWriteOperation = writeVerbs.includes(verb);
|
|
109
|
+
|
|
110
|
+
if (hasDataPrefix && isWriteOperation) {
|
|
111
|
+
issues.push({
|
|
112
|
+
type: 'rpcNaming',
|
|
113
|
+
file: relativePath,
|
|
114
|
+
line: getLineNumber(content, functionStart),
|
|
115
|
+
message: `RPC '${functionName}' has 'data_' prefix but uses write verb '${verb}'. Use 'app_' prefix for write operations.`,
|
|
116
|
+
code: getCodeSnippet(content, functionStart, 0, 100),
|
|
117
|
+
severity: 'error',
|
|
118
|
+
fix: `Rename to app_${functionName.replace('data_', '')}`,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (hasAppPrefix && isReadOperation) {
|
|
123
|
+
issues.push({
|
|
124
|
+
type: 'rpcNaming',
|
|
125
|
+
file: relativePath,
|
|
126
|
+
line: getLineNumber(content, functionStart),
|
|
127
|
+
message: `RPC '${functionName}' has 'app_' prefix but uses read verb '${verb}'. Use 'data_' prefix for read operations.`,
|
|
128
|
+
code: getCodeSnippet(content, functionStart, 0, 100),
|
|
129
|
+
severity: 'error',
|
|
130
|
+
fix: `Rename to data_${functionName.replace('app_', '')}`,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
} catch (error) {
|
|
135
|
+
// Skip files that can't be read
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
return issues;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Check tech stack versions
|
|
144
|
+
*/
|
|
145
|
+
function checkTechStackVersions(consumingAppPath) {
|
|
146
|
+
const issues = [];
|
|
147
|
+
|
|
148
|
+
const packageJsonPath = path.join(consumingAppPath, 'package.json');
|
|
149
|
+
const packageJsonContent = readFileSafe(packageJsonPath);
|
|
150
|
+
|
|
151
|
+
if (!packageJsonContent) {
|
|
152
|
+
return issues;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
let packageJson;
|
|
156
|
+
try {
|
|
157
|
+
packageJson = JSON.parse(packageJsonContent);
|
|
158
|
+
} catch (error) {
|
|
159
|
+
return issues;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const allDeps = {
|
|
163
|
+
...(packageJson.dependencies || {}),
|
|
164
|
+
...(packageJson.devDependencies || {}),
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// Get pace-core package.json for peer dependencies
|
|
168
|
+
const paceCorePath = findPaceCorePackageJson(consumingAppPath);
|
|
169
|
+
if (!paceCorePath) {
|
|
170
|
+
return issues;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const paceCorePkg = JSON.parse(fs.readFileSync(paceCorePath, 'utf8'));
|
|
174
|
+
const peerDeps = paceCorePkg.peerDependencies || {};
|
|
175
|
+
|
|
176
|
+
// Check required peer dependencies
|
|
177
|
+
const requiredPeers = ['react', 'react-dom', 'react-router-dom'];
|
|
178
|
+
|
|
179
|
+
requiredPeers.forEach(dep => {
|
|
180
|
+
if (!allDeps[dep]) {
|
|
181
|
+
issues.push({
|
|
182
|
+
type: 'techStack',
|
|
183
|
+
file: 'package.json',
|
|
184
|
+
line: 1,
|
|
185
|
+
message: `Missing required dependency: ${dep}. Required version: ${peerDeps[dep] || 'latest'}`,
|
|
186
|
+
severity: 'error',
|
|
187
|
+
fix: `Install ${dep}: npm install ${dep}@${peerDeps[dep] || 'latest'}`,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Check React 19+ requirement
|
|
193
|
+
if (allDeps.react) {
|
|
194
|
+
const reactVersion = allDeps.react.replace(/[\^~]/, '');
|
|
195
|
+
const reactMajor = parseInt(reactVersion.split('.')[0]);
|
|
196
|
+
|
|
197
|
+
if (reactMajor < 19) {
|
|
198
|
+
issues.push({
|
|
199
|
+
type: 'techStack',
|
|
200
|
+
file: 'package.json',
|
|
201
|
+
line: 1,
|
|
202
|
+
message: `React version ${reactVersion} is below required version 19+. pace-core requires React 19+.`,
|
|
203
|
+
severity: 'error',
|
|
204
|
+
fix: 'Upgrade React: npm install react@^19.0.0 react-dom@^19.0.0',
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return issues;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Check Vite configuration (optimizeDeps, resolve.dedupe)
|
|
214
|
+
*/
|
|
215
|
+
function checkViteConfig(consumingAppPath) {
|
|
216
|
+
const issues = [];
|
|
217
|
+
|
|
218
|
+
const viteConfigFiles = findConfigFiles(consumingAppPath, ['vite.config.ts', 'vite.config.js']);
|
|
219
|
+
const viteConfigPath = viteConfigFiles['vite.config.ts'] || viteConfigFiles['vite.config.js'];
|
|
220
|
+
|
|
221
|
+
if (!viteConfigPath) {
|
|
222
|
+
return issues; // No vite config, skip
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const content = readFileSafe(viteConfigPath);
|
|
226
|
+
if (!content) {
|
|
227
|
+
return issues;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const relativePath = getRelativePath(viteConfigPath, consumingAppPath);
|
|
231
|
+
|
|
232
|
+
// Check for optimizeDeps.exclude (should exclude pace-core and react-router-dom)
|
|
233
|
+
const hasOptimizeDepsExclude = /optimizeDeps\s*:\s*\{[^}]*exclude/.test(content);
|
|
234
|
+
if (!hasOptimizeDepsExclude) {
|
|
235
|
+
issues.push({
|
|
236
|
+
type: 'viteConfig',
|
|
237
|
+
file: relativePath,
|
|
238
|
+
line: 1,
|
|
239
|
+
message: 'vite.config.ts missing optimizeDeps.exclude. Should exclude @jmruthers/pace-core and react-router-dom to prevent React context mismatches.',
|
|
240
|
+
severity: 'warning',
|
|
241
|
+
fix: 'Add: optimizeDeps: { exclude: [\'@jmruthers/pace-core\', \'react-router-dom\'] }',
|
|
242
|
+
});
|
|
243
|
+
} else {
|
|
244
|
+
// Check if pace-core is excluded
|
|
245
|
+
const excludesPaceCore = /exclude\s*:\s*\[[^\]]*['"]@jmruthers\/pace-core['"]/.test(content);
|
|
246
|
+
if (!excludesPaceCore) {
|
|
247
|
+
issues.push({
|
|
248
|
+
type: 'viteConfig',
|
|
249
|
+
file: relativePath,
|
|
250
|
+
line: 1,
|
|
251
|
+
message: 'vite.config.ts optimizeDeps.exclude should include @jmruthers/pace-core to prevent React context mismatches.',
|
|
252
|
+
severity: 'warning',
|
|
253
|
+
fix: 'Add \'@jmruthers/pace-core\' to optimizeDeps.exclude array',
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Check for resolve.dedupe (should dedupe React dependencies)
|
|
259
|
+
// Need to handle nested objects, so look for dedupe anywhere after resolve: {
|
|
260
|
+
// Match resolve: { ... and then look for dedupe before the matching closing brace
|
|
261
|
+
// Use a more flexible pattern that handles nested braces
|
|
262
|
+
const resolvePattern = /resolve\s*:\s*\{/;
|
|
263
|
+
const resolveMatch = content.match(resolvePattern);
|
|
264
|
+
|
|
265
|
+
let hasResolveDedupe = false;
|
|
266
|
+
if (resolveMatch) {
|
|
267
|
+
const resolveStart = resolveMatch.index + resolveMatch[0].length;
|
|
268
|
+
// Find the matching closing brace for the resolve object
|
|
269
|
+
let braceCount = 1;
|
|
270
|
+
let i = resolveStart;
|
|
271
|
+
let resolveEnd = -1;
|
|
272
|
+
|
|
273
|
+
while (i < content.length && braceCount > 0) {
|
|
274
|
+
if (content[i] === '{') braceCount++;
|
|
275
|
+
if (content[i] === '}') braceCount--;
|
|
276
|
+
if (braceCount === 0) {
|
|
277
|
+
resolveEnd = i;
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
i++;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (resolveEnd > 0) {
|
|
284
|
+
const resolveBody = content.substring(resolveStart, resolveEnd);
|
|
285
|
+
// Check if dedupe exists in the resolve object body
|
|
286
|
+
hasResolveDedupe = /dedupe\s*:/.test(resolveBody);
|
|
287
|
+
|
|
288
|
+
// Also verify it includes the required dependencies
|
|
289
|
+
if (hasResolveDedupe) {
|
|
290
|
+
const dedupePattern = /dedupe\s*:\s*\[([^\]]+)\]/;
|
|
291
|
+
const dedupeMatch = resolveBody.match(dedupePattern);
|
|
292
|
+
if (dedupeMatch) {
|
|
293
|
+
const dedupeArray = dedupeMatch[1];
|
|
294
|
+
const hasReact = /['"]react['"]/.test(dedupeArray);
|
|
295
|
+
const hasReactDom = /['"]react-dom['"]/.test(dedupeArray);
|
|
296
|
+
const hasReactRouter = /['"]react-router-dom['"]/.test(dedupeArray);
|
|
297
|
+
|
|
298
|
+
// If any required dependency is missing, flag it
|
|
299
|
+
if (!hasReact || !hasReactDom || !hasReactRouter) {
|
|
300
|
+
issues.push({
|
|
301
|
+
type: 'viteConfig',
|
|
302
|
+
file: relativePath,
|
|
303
|
+
line: 1,
|
|
304
|
+
message: 'vite.config.ts resolve.dedupe is missing required dependencies. Should include: react, react-dom, react-router-dom',
|
|
305
|
+
severity: 'warning',
|
|
306
|
+
fix: 'Update resolve.dedupe to include: [\'react\', \'react-dom\', \'react-router-dom\']',
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (!hasResolveDedupe) {
|
|
315
|
+
issues.push({
|
|
316
|
+
type: 'viteConfig',
|
|
317
|
+
file: relativePath,
|
|
318
|
+
line: 1,
|
|
319
|
+
message: 'vite.config.ts missing resolve.dedupe. Should dedupe React dependencies to prevent context mismatches.',
|
|
320
|
+
severity: 'warning',
|
|
321
|
+
fix: 'Add: resolve: { dedupe: [\'react\', \'react-dom\', \'react-router-dom\'] }',
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return issues;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Run audit for Standard 7: API & Tech Stack
|
|
330
|
+
* @param {string} consumingAppPath - Path to consuming app
|
|
331
|
+
* @returns {object} - Audit results with issues array
|
|
332
|
+
*/
|
|
333
|
+
function runStandard7Audit(consumingAppPath) {
|
|
334
|
+
const issues = [];
|
|
335
|
+
|
|
336
|
+
try {
|
|
337
|
+
issues.push(...checkRPCNaming(consumingAppPath));
|
|
338
|
+
issues.push(...checkTechStackVersions(consumingAppPath));
|
|
339
|
+
issues.push(...checkViteConfig(consumingAppPath));
|
|
340
|
+
} catch (error) {
|
|
341
|
+
return {
|
|
342
|
+
standard: '07-api-tech-stack',
|
|
343
|
+
issues: [],
|
|
344
|
+
error: error.message,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return {
|
|
349
|
+
standard: '07-api-tech-stack',
|
|
350
|
+
issues,
|
|
351
|
+
error: null,
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
module.exports = { runStandard7Audit };
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard 8: Testing & Documentation Audit
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module Audit/Standard8
|
|
5
|
+
*
|
|
6
|
+
* Audits consuming apps for compliance with Standard 8: Testing & Documentation.
|
|
7
|
+
* Validates test structure, test timeout configuration, and testing tools.
|
|
8
|
+
*
|
|
9
|
+
* Reference: packages/core/docs/standards/8-testing-documentation-standards.md
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const { findConfigFiles, readFileSafe, getRelativePath, findSourceFiles, directoryExists } = require('../utils/file-utils.cjs');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Check test timeout configuration
|
|
17
|
+
*/
|
|
18
|
+
function checkTestTimeoutConfig(consumingAppPath) {
|
|
19
|
+
const issues = [];
|
|
20
|
+
|
|
21
|
+
// Check vitest.config.ts
|
|
22
|
+
const vitestConfigFiles = findConfigFiles(consumingAppPath, ['vitest.config.ts', 'vitest.config.js']);
|
|
23
|
+
const vitestConfigPath = vitestConfigFiles['vitest.config.ts'] || vitestConfigFiles['vitest.config.js'];
|
|
24
|
+
|
|
25
|
+
// Also check package.json for test scripts
|
|
26
|
+
const packageJsonPath = path.join(consumingAppPath, 'package.json');
|
|
27
|
+
const packageJsonContent = readFileSafe(packageJsonPath);
|
|
28
|
+
|
|
29
|
+
let hasTimeoutInConfig = false;
|
|
30
|
+
let hasTimeoutInScripts = false;
|
|
31
|
+
|
|
32
|
+
// Check vitest.config.ts
|
|
33
|
+
if (vitestConfigPath) {
|
|
34
|
+
const content = readFileSafe(vitestConfigPath);
|
|
35
|
+
if (content) {
|
|
36
|
+
const hasTestTimeout = /testTimeout\s*[:=]/.test(content);
|
|
37
|
+
const hasHookTimeout = /hookTimeout\s*[:=]/.test(content);
|
|
38
|
+
|
|
39
|
+
if (hasTestTimeout || hasHookTimeout) {
|
|
40
|
+
hasTimeoutInConfig = true;
|
|
41
|
+
} else {
|
|
42
|
+
const relativePath = getRelativePath(vitestConfigPath, consumingAppPath);
|
|
43
|
+
issues.push({
|
|
44
|
+
type: 'testTimeout',
|
|
45
|
+
file: relativePath,
|
|
46
|
+
line: 1,
|
|
47
|
+
message: 'vitest.config.ts missing test timeout configuration. Tests may hang indefinitely without timeouts.',
|
|
48
|
+
severity: 'error',
|
|
49
|
+
fix: 'Add: test: { testTimeout: 10000, hookTimeout: 10000, teardownTimeout: 5000 }',
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Check package.json scripts
|
|
56
|
+
if (packageJsonContent) {
|
|
57
|
+
try {
|
|
58
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
59
|
+
const scripts = packageJson.scripts || {};
|
|
60
|
+
|
|
61
|
+
const testScripts = Object.values(scripts).filter(script =>
|
|
62
|
+
typeof script === 'string' && script.includes('vitest')
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
hasTimeoutInScripts = testScripts.some(script =>
|
|
66
|
+
script.includes('--test-timeout') || script.includes('testTimeout')
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
if (!hasTimeoutInConfig && !hasTimeoutInScripts && testScripts.length > 0) {
|
|
70
|
+
issues.push({
|
|
71
|
+
type: 'testTimeout',
|
|
72
|
+
file: 'package.json',
|
|
73
|
+
line: 1,
|
|
74
|
+
message: 'Test scripts missing timeout configuration. Tests may hang indefinitely without timeouts.',
|
|
75
|
+
severity: 'error',
|
|
76
|
+
fix: 'Add --test-timeout=10000 to test scripts or configure in vitest.config.ts',
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
} catch (error) {
|
|
80
|
+
// Skip if package.json can't be parsed
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return issues;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Check testing tools (React Testing Library, userEvent, Vitest)
|
|
89
|
+
*/
|
|
90
|
+
function checkTestingTools(consumingAppPath) {
|
|
91
|
+
const issues = [];
|
|
92
|
+
|
|
93
|
+
const packageJsonPath = path.join(consumingAppPath, 'package.json');
|
|
94
|
+
const packageJsonContent = readFileSafe(packageJsonPath);
|
|
95
|
+
|
|
96
|
+
if (!packageJsonContent) {
|
|
97
|
+
return issues;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
let packageJson;
|
|
101
|
+
try {
|
|
102
|
+
packageJson = JSON.parse(packageJsonContent);
|
|
103
|
+
} catch (error) {
|
|
104
|
+
return issues;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const allDeps = {
|
|
108
|
+
...(packageJson.dependencies || {}),
|
|
109
|
+
...(packageJson.devDependencies || {}),
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// Check for required testing tools
|
|
113
|
+
const requiredTools = [
|
|
114
|
+
{ name: 'vitest', description: 'Test runner' },
|
|
115
|
+
{ name: '@testing-library/react', description: 'React Testing Library' },
|
|
116
|
+
{ name: '@testing-library/user-event', description: 'userEvent for interaction simulation' },
|
|
117
|
+
];
|
|
118
|
+
|
|
119
|
+
requiredTools.forEach(({ name, description }) => {
|
|
120
|
+
if (!allDeps[name]) {
|
|
121
|
+
issues.push({
|
|
122
|
+
type: 'testingTools',
|
|
123
|
+
file: 'package.json',
|
|
124
|
+
line: 1,
|
|
125
|
+
message: `Missing required testing tool: ${name} (${description})`,
|
|
126
|
+
severity: 'warning',
|
|
127
|
+
fix: `Install: npm install --save-dev ${name}`,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
return issues;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Check test file structure (colocation, naming)
|
|
137
|
+
*/
|
|
138
|
+
function checkTestStructure(consumingAppPath) {
|
|
139
|
+
const issues = [];
|
|
140
|
+
|
|
141
|
+
const srcDir = path.join(consumingAppPath, 'src');
|
|
142
|
+
if (!directoryExists(srcDir)) {
|
|
143
|
+
return issues;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Find all test files
|
|
147
|
+
const testFiles = findSourceFiles(srcDir).filter(file =>
|
|
148
|
+
file.includes('.test.') || file.includes('.spec.')
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
testFiles.forEach(testFile => {
|
|
152
|
+
const content = readFileSafe(testFile);
|
|
153
|
+
if (!content) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const relativePath = getRelativePath(testFile, consumingAppPath);
|
|
158
|
+
|
|
159
|
+
// Check if using .spec instead of .test
|
|
160
|
+
if (testFile.includes('.spec.')) {
|
|
161
|
+
issues.push({
|
|
162
|
+
type: 'testStructure',
|
|
163
|
+
file: relativePath,
|
|
164
|
+
line: 1,
|
|
165
|
+
message: 'Test file uses .spec extension. Should use .test extension for consistency.',
|
|
166
|
+
severity: 'warning',
|
|
167
|
+
fix: `Rename to ${testFile.replace('.spec.', '.test.')}`,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
return issues;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Run audit for Standard 8: Testing & Documentation
|
|
177
|
+
* @param {string} consumingAppPath - Path to consuming app
|
|
178
|
+
* @returns {object} - Audit results with issues array
|
|
179
|
+
*/
|
|
180
|
+
function runStandard8Audit(consumingAppPath) {
|
|
181
|
+
const issues = [];
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
issues.push(...checkTestTimeoutConfig(consumingAppPath));
|
|
185
|
+
issues.push(...checkTestingTools(consumingAppPath));
|
|
186
|
+
issues.push(...checkTestStructure(consumingAppPath));
|
|
187
|
+
} catch (error) {
|
|
188
|
+
return {
|
|
189
|
+
standard: '08-testing-documentation',
|
|
190
|
+
issues: [],
|
|
191
|
+
error: error.message,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
standard: '08-testing-documentation',
|
|
197
|
+
issues,
|
|
198
|
+
error: null,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
module.exports = { runStandard8Audit };
|