chore(web): add default frontend oxc tooling (#5585)
- add oxlint and oxfmt configuration for web/default quality checks - replace ESLint and Prettier scripts with protected-header Oxc formatting - update frontend workspace dependencies for oxlint and oxfmt
This commit is contained in:
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxfmt/configuration_schema.json",
|
||||
"arrowParens": "always",
|
||||
"bracketSpacing": true,
|
||||
"endOfLine": "lf",
|
||||
"insertFinalNewline": true,
|
||||
"jsxSingleQuote": true,
|
||||
"printWidth": 80,
|
||||
"quoteProps": "as-needed",
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"sortImports": true,
|
||||
"sortPackageJson": true,
|
||||
"sortTailwindcss": true,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "es5",
|
||||
"ignorePatterns": [
|
||||
"node_modules",
|
||||
"dist",
|
||||
"build",
|
||||
"coverage",
|
||||
".tanstack",
|
||||
".eslintrc.cjs",
|
||||
"**/routeTree.gen.ts",
|
||||
"src/routeTree.gen.ts"
|
||||
]
|
||||
}
|
||||
Vendored
+207
@@ -0,0 +1,207 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
||||
"plugins": ["typescript", "unicorn", "oxc", "react", "import", "promise"],
|
||||
"categories": {
|
||||
"correctness": "error"
|
||||
},
|
||||
"env": {
|
||||
"browser": true,
|
||||
"builtin": true,
|
||||
"es2024": true,
|
||||
"node": true
|
||||
},
|
||||
"ignorePatterns": [
|
||||
"node_modules",
|
||||
"dist",
|
||||
"build",
|
||||
"coverage",
|
||||
".tanstack",
|
||||
".eslintrc.cjs",
|
||||
"src/components/ui",
|
||||
"src/routeTree.gen.ts"
|
||||
],
|
||||
"rules": {
|
||||
"curly": "error",
|
||||
"eqeqeq": [
|
||||
"error",
|
||||
"always",
|
||||
{
|
||||
"null": "ignore"
|
||||
}
|
||||
],
|
||||
"import/first": "warn",
|
||||
"import/newline-after-import": "warn",
|
||||
"import/no-cycle": "warn",
|
||||
"import/no-duplicates": [
|
||||
"error",
|
||||
{
|
||||
"preferInline": true
|
||||
}
|
||||
],
|
||||
"import/no-unassigned-import": "off",
|
||||
"no-array-constructor": "error",
|
||||
"no-console": "warn",
|
||||
"no-duplicate-imports": "error",
|
||||
"no-nested-ternary": "error",
|
||||
"no-new-wrappers": "error",
|
||||
"no-regex-spaces": "error",
|
||||
"no-unsafe-finally": "warn",
|
||||
"no-unsafe-negation": "error",
|
||||
"no-unused-expressions": "warn",
|
||||
"no-unused-labels": "error",
|
||||
"no-unused-vars": [
|
||||
"warn",
|
||||
{
|
||||
"args": "all",
|
||||
"argsIgnorePattern": "^_",
|
||||
"caughtErrors": "all",
|
||||
"caughtErrorsIgnorePattern": "^_",
|
||||
"destructuredArrayIgnorePattern": "^_",
|
||||
"varsIgnorePattern": "^_",
|
||||
"ignoreRestSiblings": true
|
||||
}
|
||||
],
|
||||
"no-useless-catch": "warn",
|
||||
"no-useless-computed-key": "error",
|
||||
"no-useless-escape": "warn",
|
||||
"no-useless-rename": "warn",
|
||||
"no-var": "warn",
|
||||
"object-shorthand": "warn",
|
||||
"oxc/const-comparisons": "error",
|
||||
"prefer-const": "warn",
|
||||
"prefer-object-has-own": "warn",
|
||||
"prefer-object-spread": "warn",
|
||||
"prefer-template": "warn",
|
||||
"promise/catch-or-return": "error",
|
||||
"promise/no-callback-in-promise": "error",
|
||||
"promise/no-new-statics": "error",
|
||||
"promise/no-return-wrap": "warn",
|
||||
"promise/valid-params": "warn",
|
||||
"react/button-has-type": "error",
|
||||
"react/checked-requires-onchange-or-readonly": "warn",
|
||||
"react/exhaustive-deps": "error",
|
||||
"react/iframe-missing-sandbox": "error",
|
||||
"react/jsx-boolean-value": "warn",
|
||||
"react/jsx-curly-brace-presence": "warn",
|
||||
"react/jsx-fragments": "warn",
|
||||
"react/jsx-key": "warn",
|
||||
"react/jsx-no-duplicate-props": "error",
|
||||
"react/jsx-no-target-blank": "warn",
|
||||
"react/jsx-no-undef": "error",
|
||||
"react/jsx-no-useless-fragment": "error",
|
||||
"react/jsx-props-no-spread-multi": "warn",
|
||||
"react/no-array-index-key": "error",
|
||||
"react/no-danger": "warn",
|
||||
"react/no-unknown-property": "warn",
|
||||
"react/no-unstable-nested-components": [
|
||||
"error",
|
||||
{
|
||||
"allowAsProps": true
|
||||
}
|
||||
],
|
||||
"react/only-export-components": [
|
||||
"error",
|
||||
{
|
||||
"allowConstantExport": true,
|
||||
"allowExportNames": [
|
||||
"getAuthSectionNavItems",
|
||||
"getAuthSectionContent",
|
||||
"getAuthSectionMeta",
|
||||
"getBillingSectionNavItems",
|
||||
"getBillingSectionContent",
|
||||
"getBillingSectionMeta",
|
||||
"getContentSectionNavItems",
|
||||
"getContentSectionContent",
|
||||
"getContentSectionMeta",
|
||||
"getDashboardSectionNavItems",
|
||||
"getModelsSectionNavItems",
|
||||
"getModelsSectionContent",
|
||||
"getModelsSectionMeta",
|
||||
"getOperationsSectionNavItems",
|
||||
"getOperationsSectionContent",
|
||||
"getOperationsSectionMeta",
|
||||
"getSecuritySectionNavItems",
|
||||
"getSecuritySectionContent",
|
||||
"getSecuritySectionMeta",
|
||||
"getSiteSectionNavItems",
|
||||
"getSiteSectionContent",
|
||||
"getSiteSectionMeta",
|
||||
"getUsageLogsSectionNavItems",
|
||||
"isUsageLogsSectionId",
|
||||
"useSuppressSettingsSectionHeader"
|
||||
]
|
||||
}
|
||||
],
|
||||
"react/react-in-jsx-scope": "off",
|
||||
"react/rules-of-hooks": "warn",
|
||||
"react/self-closing-comp": "warn",
|
||||
"typescript/consistent-type-imports": [
|
||||
"error",
|
||||
{
|
||||
"prefer": "type-imports",
|
||||
"fixStyle": "inline-type-imports",
|
||||
"disallowTypeAnnotations": false
|
||||
}
|
||||
],
|
||||
"typescript/no-duplicate-type-constituents": "error",
|
||||
"typescript/no-explicit-any": "warn",
|
||||
"typescript/no-extra-non-null-assertion": "error",
|
||||
"typescript/no-import-type-side-effects": "error",
|
||||
"typescript/no-non-null-assertion": "error",
|
||||
"typescript/no-require-imports": "error",
|
||||
"typescript/no-unnecessary-template-expression": "error",
|
||||
"typescript/no-unnecessary-type-arguments": "error",
|
||||
"typescript/no-unnecessary-type-assertion": "error",
|
||||
"typescript/no-useless-empty-export": "error",
|
||||
"typescript/no-wrapper-object-types": "error",
|
||||
"typescript/prefer-as-const": "error",
|
||||
"typescript/prefer-namespace-keyword": "error",
|
||||
"unicorn/no-single-promise-in-promise-methods": "error",
|
||||
"unicorn/no-unnecessary-await": "error",
|
||||
"unicorn/no-useless-fallback-in-spread": "warn",
|
||||
"unicorn/no-useless-length-check": "warn",
|
||||
"unicorn/no-useless-promise-resolve-reject": "warn",
|
||||
"unicorn/no-useless-spread": "error",
|
||||
"unicorn/prefer-add-event-listener": "warn",
|
||||
"unicorn/prefer-array-find": "warn",
|
||||
"unicorn/prefer-array-flat": "warn",
|
||||
"unicorn/prefer-array-flat-map": "warn",
|
||||
"unicorn/prefer-array-index-of": "warn",
|
||||
"unicorn/prefer-array-some": "warn",
|
||||
"unicorn/prefer-at": "error",
|
||||
"unicorn/prefer-date-now": "warn",
|
||||
"unicorn/prefer-includes": "warn",
|
||||
"unicorn/prefer-keyboard-event-key": "warn",
|
||||
"unicorn/prefer-modern-dom-apis": "warn",
|
||||
"unicorn/prefer-module": "warn",
|
||||
"unicorn/prefer-node-protocol": "warn",
|
||||
"unicorn/prefer-number-properties": "warn",
|
||||
"unicorn/prefer-object-from-entries": "warn",
|
||||
"unicorn/prefer-optional-catch-binding": "error",
|
||||
"unicorn/prefer-query-selector": "warn",
|
||||
"unicorn/prefer-regexp-test": "warn",
|
||||
"unicorn/prefer-set-has": "warn",
|
||||
"unicorn/prefer-spread": "error",
|
||||
"unicorn/prefer-string-replace-all": "error",
|
||||
"unicorn/prefer-string-slice": "warn",
|
||||
"unicorn/prefer-string-starts-ends-with": "warn",
|
||||
"unicorn/prefer-string-trim-start-end": "warn",
|
||||
"unicorn/prefer-structured-clone": "warn",
|
||||
"unicorn/throw-new-error": "error"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["src/routes/**/*.{ts,tsx}"],
|
||||
"rules": {
|
||||
"react/only-export-components": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["**/scripts/**/*.{js,mjs,cjs}"],
|
||||
"rules": {
|
||||
"no-console": "off",
|
||||
"prefer-node-protocol": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
-18
@@ -1,18 +0,0 @@
|
||||
# Ignore everything
|
||||
/*
|
||||
|
||||
# Except these files & folders
|
||||
!/src
|
||||
!index.html
|
||||
!package.json
|
||||
!tailwind.config.js
|
||||
!tsconfig.json
|
||||
!tsconfig.node.json
|
||||
!vite.config.ts
|
||||
!.prettierrc
|
||||
!README.md
|
||||
!eslint.config.js
|
||||
!postcss.config.js
|
||||
|
||||
# Ignore auto generated routeTree.gen.ts
|
||||
/src/routeTree.gen.ts
|
||||
Vendored
-49
@@ -1,49 +0,0 @@
|
||||
{
|
||||
"arrowParens": "always",
|
||||
"semi": false,
|
||||
"tabWidth": 2,
|
||||
"printWidth": 80,
|
||||
"singleQuote": true,
|
||||
"jsxSingleQuote": true,
|
||||
"trailingComma": "es5",
|
||||
"bracketSpacing": true,
|
||||
"endOfLine": "lf",
|
||||
"plugins": [
|
||||
"@trivago/prettier-plugin-sort-imports",
|
||||
"prettier-plugin-tailwindcss"
|
||||
],
|
||||
"importOrder": [
|
||||
"^path$",
|
||||
"^vite$",
|
||||
"^@vitejs/(.*)$",
|
||||
"^react$",
|
||||
"^react-dom/client$",
|
||||
"^react/(.*)$",
|
||||
"^globals$",
|
||||
"^zod$",
|
||||
"^axios$",
|
||||
"^dayjs$",
|
||||
"^react-hook-form$",
|
||||
"^use-intl$",
|
||||
"^@radix-ui/(.*)$",
|
||||
"^@hookform/resolvers/zod$",
|
||||
"^@tanstack/react-query$",
|
||||
"^@tanstack/react-router$",
|
||||
"^@tanstack/react-table$",
|
||||
"<THIRD_PARTY_MODULES>",
|
||||
"^@/assets/(.*)",
|
||||
"^@/api/(.*)$",
|
||||
"^@/stores/(.*)$",
|
||||
"^@/lib/(.*)$",
|
||||
"^@/utils/(.*)$",
|
||||
"^@/constants/(.*)$",
|
||||
"^@/context/(.*)$",
|
||||
"^@/hooks/(.*)$",
|
||||
"^@/components/layouts/(.*)$",
|
||||
"^@/components/ui/(.*)$",
|
||||
"^@/components/errors/(.*)$",
|
||||
"^@/components/(.*)$",
|
||||
"^@/features/(.*)$",
|
||||
"^[./]"
|
||||
]
|
||||
}
|
||||
Vendored
+1
-1
@@ -20,7 +20,7 @@
|
||||
| UI 与样式 | Base UI、Hugeicons、Tailwind CSS、clsx / class-variance-authority |
|
||||
| 表单 | React Hook Form、Zod |
|
||||
| 图表 | @visactor/vchart、@visactor/react-vchart |
|
||||
| 工具 | qrcode.react、prettier、eslint、vitest(可选)|
|
||||
| 工具 | qrcode.react、oxfmt、oxlint、vitest(可选)|
|
||||
|
||||
优先选用成熟、维护良好的开源库;仅在现有库无法满足或需特殊适配时自行实现,并评估可维护性与通用性。
|
||||
|
||||
|
||||
Vendored
-67
@@ -1,67 +0,0 @@
|
||||
import globals from 'globals'
|
||||
import js from '@eslint/js'
|
||||
import pluginQuery from '@tanstack/eslint-plugin-query'
|
||||
import reactHooks from 'eslint-plugin-react-hooks'
|
||||
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||
import { defineConfig } from 'eslint/config'
|
||||
import tseslint from 'typescript-eslint'
|
||||
|
||||
export default defineConfig(
|
||||
{ ignores: ['dist', 'src/components/ui'] },
|
||||
{
|
||||
extends: [
|
||||
js.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
...pluginQuery.configs['flat/recommended'],
|
||||
],
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
},
|
||||
plugins: {
|
||||
'react-hooks': reactHooks,
|
||||
'react-refresh': reactRefresh,
|
||||
},
|
||||
rules: {
|
||||
...reactHooks.configs.recommended.rules,
|
||||
'react-hooks/incompatible-library': 'off',
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
'no-console': 'error',
|
||||
'no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{
|
||||
args: 'all',
|
||||
argsIgnorePattern: '^_',
|
||||
caughtErrors: 'all',
|
||||
caughtErrorsIgnorePattern: '^_',
|
||||
destructuredArrayIgnorePattern: '^_',
|
||||
varsIgnorePattern: '^_',
|
||||
ignoreRestSiblings: true,
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/consistent-type-imports': [
|
||||
'error',
|
||||
{
|
||||
prefer: 'type-imports',
|
||||
fixStyle: 'inline-type-imports',
|
||||
disallowTypeAnnotations: false,
|
||||
},
|
||||
],
|
||||
'no-duplicate-imports': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['src/routes/**/*.{ts,tsx}'],
|
||||
plugins: {
|
||||
'react-refresh': reactRefresh,
|
||||
},
|
||||
rules: {
|
||||
'react-refresh/only-export-components': 'off',
|
||||
},
|
||||
}
|
||||
)
|
||||
Vendored
+8
-15
@@ -1,17 +1,18 @@
|
||||
{
|
||||
"name": "newapi-web",
|
||||
"private": false,
|
||||
"version": "1.0.0",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "rsbuild dev",
|
||||
"build": "rsbuild build",
|
||||
"build:check": "tsc -b && rsbuild build",
|
||||
"typecheck": "tsc -b",
|
||||
"lint": "eslint .",
|
||||
"lint": "oxlint -c .oxlintrc.json .",
|
||||
"lint:fix": "oxlint -c .oxlintrc.json . --fix",
|
||||
"preview": "rsbuild preview",
|
||||
"format:check": "prettier --check .",
|
||||
"format": "prettier --write .",
|
||||
"format:check": "node scripts/format-with-protected-headers.mjs --check",
|
||||
"format": "node scripts/format-with-protected-headers.mjs --write",
|
||||
"copyright:check": "node scripts/add-copyright.mjs --check",
|
||||
"copyright": "node scripts/add-copyright.mjs",
|
||||
"i18n:sync": "node scripts/sync-i18n.mjs",
|
||||
@@ -74,29 +75,21 @@
|
||||
"zustand": "^5.0.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@rsbuild/core": "^2.0.7",
|
||||
"@rsbuild/plugin-react": "^2.0.0",
|
||||
"@tanstack/eslint-plugin-query": "^5.100.14",
|
||||
"@tanstack/react-query-devtools": "^5.100.14",
|
||||
"@tanstack/react-router-devtools": "^1.167.0",
|
||||
"@tanstack/router-plugin": "^1.168.11",
|
||||
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
||||
"@types/node": "^25.9.1",
|
||||
"@types/react": "^19.2.15",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@xyflow/react": "^12.10.2",
|
||||
"embla-carousel-react": "^8.6.0",
|
||||
"eslint": "^10.4.0",
|
||||
"eslint-plugin-react-hooks": "^7.1.1",
|
||||
"eslint-plugin-react-refresh": "^0.5.2",
|
||||
"globals": "^17.6.0",
|
||||
"knip": "^6.14.2",
|
||||
"prettier": "catalog:",
|
||||
"prettier-plugin-tailwindcss": "^0.8.0",
|
||||
"oxfmt": "catalog:",
|
||||
"oxlint": "catalog:",
|
||||
"shadcn": "^4.8.0",
|
||||
"typescript": "~6.0.3",
|
||||
"typescript-eslint": "^8.59.4"
|
||||
"typescript": "~6.0.3"
|
||||
},
|
||||
"overrides": {
|
||||
"brace-expansion": "2.1.1",
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
Copyright (C) 2023-2026 QuantumNous
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
For commercial licensing, please contact support@quantumnous.com
|
||||
*/
|
||||
import { spawnSync } from 'node:child_process'
|
||||
import { readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'
|
||||
import { join, relative } from 'node:path'
|
||||
|
||||
const mode = process.argv[2]
|
||||
|
||||
if (mode !== '--check' && mode !== '--write') {
|
||||
console.error(
|
||||
'Usage: node scripts/format-with-protected-headers.mjs --check|--write'
|
||||
)
|
||||
process.exit(2)
|
||||
}
|
||||
|
||||
const root = process.cwd()
|
||||
const excludedDirs = new Set([
|
||||
'.git',
|
||||
'.tanstack',
|
||||
'build',
|
||||
'coverage',
|
||||
'dist',
|
||||
'node_modules',
|
||||
])
|
||||
const headerExtensions = new Set([
|
||||
'.cjs',
|
||||
'.cts',
|
||||
'.js',
|
||||
'.jsx',
|
||||
'.mjs',
|
||||
'.mts',
|
||||
'.ts',
|
||||
'.tsx',
|
||||
])
|
||||
const protectedHeaderPattern =
|
||||
/^\/\*\nCopyright \(C\)[\s\S]*?QuantumNous[\s\S]*?\*\/\n+/
|
||||
|
||||
function extensionOf(path) {
|
||||
const index = path.lastIndexOf('.')
|
||||
return index === -1 ? '' : path.slice(index)
|
||||
}
|
||||
|
||||
function walk(dir, files = []) {
|
||||
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
||||
if (entry.isDirectory()) {
|
||||
if (!excludedDirs.has(entry.name)) {
|
||||
walk(join(dir, entry.name), files)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if (entry.isFile()) {
|
||||
files.push(join(dir, entry.name))
|
||||
}
|
||||
}
|
||||
|
||||
return files
|
||||
}
|
||||
|
||||
function snapshotFiles(files) {
|
||||
const snapshot = new Map()
|
||||
for (const file of files) {
|
||||
snapshot.set(file, readFileSync(file))
|
||||
}
|
||||
return snapshot
|
||||
}
|
||||
|
||||
function restoreSnapshot(snapshot) {
|
||||
for (const [file, content] of snapshot) {
|
||||
writeFileSync(file, content)
|
||||
}
|
||||
}
|
||||
|
||||
function stripProtectedHeaders(files) {
|
||||
const headers = new Map()
|
||||
|
||||
for (const file of files) {
|
||||
if (!headerExtensions.has(extensionOf(file))) {
|
||||
continue
|
||||
}
|
||||
|
||||
const content = readFileSync(file, 'utf8')
|
||||
const match = content.match(protectedHeaderPattern)
|
||||
if (!match) {
|
||||
continue
|
||||
}
|
||||
|
||||
headers.set(file, match[0])
|
||||
writeFileSync(file, content.slice(match[0].length))
|
||||
}
|
||||
|
||||
return headers
|
||||
}
|
||||
|
||||
function restoreProtectedHeaders(headers) {
|
||||
for (const [file, header] of headers) {
|
||||
const content = readFileSync(file, 'utf8').replace(/^\n+/, '')
|
||||
if (!content.startsWith(header)) {
|
||||
writeFileSync(file, header + content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function listChangedFiles(before, files) {
|
||||
const changed = []
|
||||
|
||||
for (const file of files) {
|
||||
const previous = before.get(file)
|
||||
const current = readFileSync(file)
|
||||
if (!previous || !previous.equals(current)) {
|
||||
changed.push(relative(root, file))
|
||||
}
|
||||
}
|
||||
|
||||
return changed
|
||||
}
|
||||
|
||||
const files = walk(root).filter(
|
||||
(file) => statSync(file).size < 10 * 1024 * 1024
|
||||
)
|
||||
const before = mode === '--check' ? snapshotFiles(files) : null
|
||||
let headers = new Map()
|
||||
let exitCode = 0
|
||||
|
||||
try {
|
||||
headers = stripProtectedHeaders(files)
|
||||
const result = spawnSync(
|
||||
'oxfmt',
|
||||
['-c', '.oxfmtrc.json', '--ignore-path', '.gitignore', '--write', '.'],
|
||||
{
|
||||
cwd: root,
|
||||
stdio: 'inherit',
|
||||
}
|
||||
)
|
||||
exitCode = result.status ?? 1
|
||||
restoreProtectedHeaders(headers)
|
||||
|
||||
if (mode === '--check' && exitCode === 0) {
|
||||
const changed = listChangedFiles(before, files)
|
||||
if (changed.length > 0) {
|
||||
console.error('Format issues found in protected-header-safe check:')
|
||||
for (const file of changed) {
|
||||
console.error(file)
|
||||
}
|
||||
exitCode = 1
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (mode === '--check' && before) {
|
||||
restoreSnapshot(before)
|
||||
} else {
|
||||
restoreProtectedHeaders(headers)
|
||||
}
|
||||
}
|
||||
|
||||
process.exit(exitCode)
|
||||
Reference in New Issue
Block a user