@nitra/cursor 1.8.94 → 1.8.96
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/mdc/graphql.mdc +33 -0
- package/mdc/js-lint.mdc +14 -3
- package/package.json +1 -1
- package/scripts/check-graphql.mjs +97 -0
- package/scripts/check-js-lint.mjs +85 -4
- package/scripts/utils/graphql-gql-scan.mjs +115 -0
package/mdc/graphql.mdc
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: GraphQL у коді (tagged template `gql`) — GraphQL Config і розширення VS Code
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
version: '1.0'
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Якщо в **`.vue`** або в **JavaScript / TypeScript** джерелах (`.js`, `.mjs`, `.cjs`, `.ts`, `.tsx`, `.jsx` тощо) зустрічається **tagged template literal** з тегом **`gql`** (типово `gql\`query …\`` для GraphQL-запиту), у **корені репозиторію** має бути файл **`.graphqlrc.yml`** ([GraphQL Config](https://the-guild.dev/graphql/config/docs)), а в **`.vscode/extensions.json`** у масиві **`recommendations`** — запис **`graphql.vscode-graphql`**, щоб підсвітка, навігація до схеми й діагностика працювали в редакторі.
|
|
8
|
+
|
|
9
|
+
Деталі виявлення `gql` у скриптах (у т.ч. лише `<script>` у SFC) — **`npm/scripts/check-graphql.mjs`** / **`npm/scripts/utils/graphql-gql-scan.mjs`**.
|
|
10
|
+
|
|
11
|
+
## `.graphqlrc.yml`
|
|
12
|
+
|
|
13
|
+
Підстав свої шляхи до схеми та до файлів з операціями; приклад орієнтиру:
|
|
14
|
+
|
|
15
|
+
```yaml title=".graphqlrc.yml"
|
|
16
|
+
schema: schema.graphql
|
|
17
|
+
documents:
|
|
18
|
+
- '**/*.{vue,js,ts,tsx}'
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## `.vscode/extensions.json`
|
|
22
|
+
|
|
23
|
+
Додай **`graphql.vscode-graphql`** до наявного списку **`recommendations`** (не замінюй інші записи):
|
|
24
|
+
|
|
25
|
+
```json title=".vscode/extensions.json"
|
|
26
|
+
{
|
|
27
|
+
"recommendations": ["graphql.vscode-graphql"]
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Перевірка
|
|
32
|
+
|
|
33
|
+
`npx @nitra/cursor check graphql`
|
package/mdc/js-lint.mdc
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Перевірка JavaScript коду
|
|
3
3
|
alwaysApply: true
|
|
4
|
-
version: '1.
|
|
4
|
+
version: '1.13'
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
**oxlint**, **ESLint**, **jscpd**. У скрипті **`lint-js`** і в CI — **`bunx oxlint`**, **`bunx eslint`**, **`bunx jscpd`** (у CI без **`--fix`** для oxlint/eslint — див. приклад workflow нижче). Без **prettier** і **@nitra/prettier-config**.
|
|
7
|
+
**oxlint**, **ESLint**, **jscpd**. У скрипті **`lint-js`** і в CI — **`bunx oxlint`**, **`bunx eslint`**, **`bunx jscpd`** (у CI без **`--fix`** для oxlint/eslint — див. приклад workflow нижче). Без **prettier** і **@nitra/prettier-config**. У **`devDependencies`** має бути **`@nitra/eslint-config` мінімум `^3.5.0`** (з ним транзитивно йде **`@e18e/eslint-plugin`** для oxlint); пакет **`@e18e/eslint-plugin`** окремо не додавай. Пакети oxlint/eslint/jscpd не додавай без потреби монорепо.
|
|
8
8
|
|
|
9
9
|
```json title=".vscode/extensions.json"
|
|
10
10
|
{
|
|
@@ -22,7 +22,7 @@ version: '1.11'
|
|
|
22
22
|
"lint-js": "bunx oxlint --fix && bunx eslint --fix . && bunx jscpd ."
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@nitra/eslint-config": "^3.
|
|
25
|
+
"@nitra/eslint-config": "^3.5.0"
|
|
26
26
|
},
|
|
27
27
|
"engines": {
|
|
28
28
|
"node": ">=24"
|
|
@@ -30,6 +30,17 @@ version: '1.11'
|
|
|
30
30
|
}
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
+
У корені має бути **`.oxlintrc.json`** з підключенням **`@e18e/eslint-plugin`** через **`jsPlugins`** і правилом **`e18e/prefer-includes`** зі значенням **`error`**. Модуль **`@e18e/eslint-plugin`** не оголошуй окремо в **`package.json`** — він уже в залежностях **`@nitra/eslint-config`** (з **3.5.0**), oxlint резолвить його з **`node_modules`**.
|
|
34
|
+
|
|
35
|
+
```json title=".oxlintrc.json (фрагмент)"
|
|
36
|
+
{
|
|
37
|
+
"jsPlugins": ["@e18e/eslint-plugin"],
|
|
38
|
+
"rules": {
|
|
39
|
+
"e18e/prefer-includes": "error"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
33
44
|
У корені проєкту має бути `.jscpd.json`. Мінімум: увімкнути облік `.gitignore`, ненульовий код виходу при знаходженні клонів, консольний звіт. За потреби додай `ignore` (дзеркальні каталоги, шаблони) та `minLines`, щоб відсікти дрібні збіги:
|
|
34
45
|
|
|
35
46
|
```json title=".jscpd.json"
|
package/package.json
CHANGED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Перевіряє правило graphql.mdc: наявність **`.graphqlrc.yml`** і рекомендації **`graphql.vscode-graphql`**, якщо у дереві є **`gql\`…\``**.
|
|
3
|
+
*
|
|
4
|
+
* Обхід репозиторію — **`walkDir`** від **`process.cwd()`** (пропуски як у інших check). Кандидати — **`.vue`** та **`.js`/`.ts`/`.jsx`/`.tsx`** тощо; ігнор **`.d.ts`**, **auto-imports.d.ts** тощо — **`shouldSkipFileForGqlScan`**.
|
|
5
|
+
*
|
|
6
|
+
* Виявлення **`gql`** — **oxc-parser** після витягування `<script>` з SFC (**`graphql-gql-scan.mjs`**). Якщо збігів немає — перевірка завершується успішно без вимог до конфігів.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync } from 'node:fs'
|
|
9
|
+
import { readFile } from 'node:fs/promises'
|
|
10
|
+
import { relative } from 'node:path'
|
|
11
|
+
|
|
12
|
+
import { createCheckReporter } from './utils/check-reporter.mjs'
|
|
13
|
+
import {
|
|
14
|
+
isGqlScanSourceFile,
|
|
15
|
+
shouldSkipFileForGqlScan,
|
|
16
|
+
sourceFileHasGqlTaggedTemplate
|
|
17
|
+
} from './utils/graphql-gql-scan.mjs'
|
|
18
|
+
import { walkDir } from './utils/walkDir.mjs'
|
|
19
|
+
|
|
20
|
+
/** Очікуваний файл GraphQL Config у корені (graphql.mdc). */
|
|
21
|
+
export const GRAPHQL_RC_FILENAME = '.graphqlrc.yml'
|
|
22
|
+
|
|
23
|
+
/** Розширення VS Code з graphql.mdc. */
|
|
24
|
+
export const REQUIRED_GRAPHQL_VSCODE_EXTENSION = 'graphql.vscode-graphql'
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Перевіряє graphql.mdc: умовна вимога `.graphqlrc.yml` і `graphql.vscode-graphql` за наявності `gql`…``.
|
|
28
|
+
* @returns {Promise<number>} 0 — OK, 1 — порушення
|
|
29
|
+
*/
|
|
30
|
+
export async function check() {
|
|
31
|
+
const reporter = createCheckReporter()
|
|
32
|
+
const { pass, fail } = reporter
|
|
33
|
+
|
|
34
|
+
const root = process.cwd()
|
|
35
|
+
/** @type {string[]} */
|
|
36
|
+
const candidates = []
|
|
37
|
+
await walkDir(root, absPath => {
|
|
38
|
+
const rel = relative(root, absPath).split('\\').join('/')
|
|
39
|
+
if (shouldSkipFileForGqlScan(rel) || !isGqlScanSourceFile(rel)) {
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
candidates.push(absPath)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
/** @type {string[]} */
|
|
46
|
+
const hits = []
|
|
47
|
+
for (const absPath of candidates) {
|
|
48
|
+
const rel = relative(root, absPath).split('\\').join('/')
|
|
49
|
+
const content = await readFile(absPath, 'utf8')
|
|
50
|
+
if (sourceFileHasGqlTaggedTemplate(content, rel)) {
|
|
51
|
+
hits.push(rel)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (hits.length === 0) {
|
|
56
|
+
pass(`Немає tagged template з тегом gql у .vue / JS / TS джерелах (переглянуто ${candidates.length} файлів) — .graphqlrc.yml не вимагається`)
|
|
57
|
+
return reporter.getExitCode()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
pass(`Знайдено gql\`…\` у ${hits.length} файлі(ах): ${hits.slice(0, 5).join(', ')}${hits.length > 5 ? '…' : ''}`)
|
|
61
|
+
|
|
62
|
+
if (!existsSync(GRAPHQL_RC_FILENAME)) {
|
|
63
|
+
fail(
|
|
64
|
+
`Відсутній ${GRAPHQL_RC_FILENAME} у корені — додай GraphQL Config (graphql.mdc), бо в проєкті є gql template literals`
|
|
65
|
+
)
|
|
66
|
+
} else {
|
|
67
|
+
pass(`${GRAPHQL_RC_FILENAME} існує`)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (!existsSync('.vscode/extensions.json')) {
|
|
71
|
+
fail(
|
|
72
|
+
'.vscode/extensions.json не існує — створи файл і додай у recommendations graphql.vscode-graphql (graphql.mdc)'
|
|
73
|
+
)
|
|
74
|
+
} else {
|
|
75
|
+
let ext
|
|
76
|
+
try {
|
|
77
|
+
ext = JSON.parse(await readFile('.vscode/extensions.json', 'utf8'))
|
|
78
|
+
} catch {
|
|
79
|
+
fail('.vscode/extensions.json не є валідним JSON')
|
|
80
|
+
ext = null
|
|
81
|
+
}
|
|
82
|
+
if (ext) {
|
|
83
|
+
const rec = ext.recommendations
|
|
84
|
+
if (!Array.isArray(rec)) {
|
|
85
|
+
fail('.vscode/extensions.json: поле recommendations має бути масивом')
|
|
86
|
+
} else if (!rec.includes(REQUIRED_GRAPHQL_VSCODE_EXTENSION)) {
|
|
87
|
+
fail(
|
|
88
|
+
`.vscode/extensions.json: додай у recommendations "${REQUIRED_GRAPHQL_VSCODE_EXTENSION}" (graphql.mdc)`
|
|
89
|
+
)
|
|
90
|
+
} else {
|
|
91
|
+
pass(`.vscode/extensions.json: є ${REQUIRED_GRAPHQL_VSCODE_EXTENSION}`)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return reporter.getExitCode()
|
|
97
|
+
}
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* Перевіряє лінт JavaScript за правилом js-lint.mdc.
|
|
3
3
|
*
|
|
4
4
|
* Канонічний `lint-js`, flat ESLint з getConfig і ignore для auto-imports, рекомендації VSCode,
|
|
5
|
-
* `.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* `.oxlintrc.json` з `jsPlugins` (`@e18e/eslint-plugin`) і правилом `e18e/prefer-includes: error`,
|
|
6
|
+
* `@nitra/eslint-config` у devDependencies мінімум **3.5.0** (транзитивний `@e18e/eslint-plugin` для oxlint), `.jscpd.json`
|
|
7
|
+
* (gitignore, exitCode, reporters, minLines), workflow `lint-js.yml` (checkout@v6, setup-bun-deps,
|
|
8
|
+
* bunx без --fix), без prettier, `engines.node` >= 24. Дубль перевірки JS у `lint.yml` — заборонено.
|
|
8
9
|
*/
|
|
9
10
|
import { existsSync } from 'node:fs'
|
|
10
11
|
import { readFile } from 'node:fs/promises'
|
|
@@ -36,6 +37,55 @@ export function isCanonicalLintJs(script) {
|
|
|
36
37
|
return normalizeLintJsScript(script) === CANONICAL_LINT_JS
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Чи діапазон `@nitra/eslint-config` у `package.json` передбачає версію з транзитивним `@e18e/eslint-plugin` (>=3.5.0).
|
|
42
|
+
*
|
|
43
|
+
* @param {unknown} versionSpec значення `devDependencies['@nitra/eslint-config']`
|
|
44
|
+
* @returns {boolean} true для `workspace:*` або першої semver у рядку >= 3.5.0
|
|
45
|
+
*/
|
|
46
|
+
export function nitraEslintConfigDeclaresE18eTransitive(versionSpec) {
|
|
47
|
+
const s = String(versionSpec).trim()
|
|
48
|
+
if (s.startsWith('workspace:')) {
|
|
49
|
+
return true
|
|
50
|
+
}
|
|
51
|
+
const m = s.match(/(\d+)\.(\d+)\.(\d+)/u)
|
|
52
|
+
if (!m) {
|
|
53
|
+
return false
|
|
54
|
+
}
|
|
55
|
+
const major = Number(m[1])
|
|
56
|
+
const minor = Number(m[2])
|
|
57
|
+
const patch = Number(m[3])
|
|
58
|
+
return major > 3 || (major === 3 && minor > 5) || (major === 3 && minor === 5 && patch >= 0)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Перевіряє обов’язкові поля `.oxlintrc.json` для плагіна e18e (js-lint.mdc).
|
|
63
|
+
*
|
|
64
|
+
* @param {unknown} cfg корінь JSON-конфігурації oxlint
|
|
65
|
+
* @returns {{ ok: boolean, failures: string[] }} `ok` і перелік повідомлень для `fail`
|
|
66
|
+
*/
|
|
67
|
+
export function verifyOxlintRcE18e(cfg) {
|
|
68
|
+
const failures = []
|
|
69
|
+
if (!cfg || typeof cfg !== 'object' || Array.isArray(cfg)) {
|
|
70
|
+
return { ok: false, failures: ['.oxlintrc.json: корінь має бути об’єктом'] }
|
|
71
|
+
}
|
|
72
|
+
const o = /** @type {Record<string, unknown>} */ (cfg)
|
|
73
|
+
const jsPlugins = o.jsPlugins
|
|
74
|
+
if (!Array.isArray(jsPlugins) || !jsPlugins.includes('@e18e/eslint-plugin')) {
|
|
75
|
+
failures.push('.oxlintrc.json: jsPlugins має містити "@e18e/eslint-plugin"')
|
|
76
|
+
}
|
|
77
|
+
const rules = o.rules
|
|
78
|
+
if (!rules || typeof rules !== 'object' || Array.isArray(rules)) {
|
|
79
|
+
failures.push('.oxlintrc.json: поле rules має бути об’єктом')
|
|
80
|
+
} else {
|
|
81
|
+
const r = /** @type {Record<string, unknown>} */ (rules)
|
|
82
|
+
if (r['e18e/prefer-includes'] !== 'error') {
|
|
83
|
+
failures.push('.oxlintrc.json: у rules має бути "e18e/prefer-includes": "error"')
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return { ok: failures.length === 0, failures }
|
|
87
|
+
}
|
|
88
|
+
|
|
39
89
|
/**
|
|
40
90
|
* Перевіряє відповідність проєкту правилам js-lint.mdc
|
|
41
91
|
* @returns {Promise<number>} 0 — все OK, 1 — є проблеми
|
|
@@ -103,8 +153,16 @@ export async function check() {
|
|
|
103
153
|
pass('package.json не містить @nitra/prettier-config')
|
|
104
154
|
}
|
|
105
155
|
|
|
106
|
-
|
|
156
|
+
const nitraEslint = pkg.devDependencies?.['@nitra/eslint-config']
|
|
157
|
+
if (nitraEslint) {
|
|
107
158
|
pass('@nitra/eslint-config є в devDependencies')
|
|
159
|
+
if (nitraEslintConfigDeclaresE18eTransitive(nitraEslint)) {
|
|
160
|
+
pass('@nitra/eslint-config: мінімум 3.5.0 (транзитивний @e18e/eslint-plugin для oxlint jsPlugins, js-lint.mdc)')
|
|
161
|
+
} else {
|
|
162
|
+
fail(
|
|
163
|
+
'@nitra/eslint-config: онови до мінімум "^3.5.0" — з цієї версії постачається @e18e/eslint-plugin для .oxlintrc.json (js-lint.mdc)'
|
|
164
|
+
)
|
|
165
|
+
}
|
|
108
166
|
} else {
|
|
109
167
|
fail('@nitra/eslint-config відсутній в devDependencies — додай: bun add -d @nitra/eslint-config')
|
|
110
168
|
}
|
|
@@ -122,6 +180,29 @@ export async function check() {
|
|
|
122
180
|
}
|
|
123
181
|
}
|
|
124
182
|
|
|
183
|
+
if (existsSync('.oxlintrc.json')) {
|
|
184
|
+
let oxCfg
|
|
185
|
+
try {
|
|
186
|
+
oxCfg = JSON.parse(await readFile('.oxlintrc.json', 'utf8'))
|
|
187
|
+
} catch {
|
|
188
|
+
fail('.oxlintrc.json не є валідним JSON')
|
|
189
|
+
oxCfg = null
|
|
190
|
+
}
|
|
191
|
+
if (oxCfg !== null) {
|
|
192
|
+
pass('.oxlintrc.json існує')
|
|
193
|
+
const oxV = verifyOxlintRcE18e(oxCfg)
|
|
194
|
+
if (oxV.ok) {
|
|
195
|
+
pass('.oxlintrc.json: jsPlugins з @e18e/eslint-plugin і e18e/prefer-includes: error')
|
|
196
|
+
} else {
|
|
197
|
+
for (const msg of oxV.failures) {
|
|
198
|
+
fail(msg)
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
} else {
|
|
203
|
+
fail('.oxlintrc.json не існує — додай конфіг oxlint (js-lint.mdc)')
|
|
204
|
+
}
|
|
205
|
+
|
|
125
206
|
if (existsSync('.vscode/extensions.json')) {
|
|
126
207
|
let ext
|
|
127
208
|
try {
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Пошук tagged template **`gql\`…\``** у джерелах для правила graphql.mdc.
|
|
3
|
+
*
|
|
4
|
+
* Для **`.vue`** береться лише вміст `<script>` / `<script setup>` (спільна логіка з **vue-forbidden-imports**).
|
|
5
|
+
* Семантику визначає **oxc-parser** (`program`): рекурсивний обхід AST, збіг лише для **Identifier** з іменем **`gql`** як тега шаблону.
|
|
6
|
+
*/
|
|
7
|
+
import { parseSync } from 'oxc-parser'
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
contentForVueImportScan,
|
|
11
|
+
isVueImportScanSourceFile,
|
|
12
|
+
shouldSkipFileForVueImportScan
|
|
13
|
+
} from './vue-forbidden-imports.mjs'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Мова для Oxc за шляхом файлу (розширення).
|
|
17
|
+
* @param {string} filePath віртуальний або реальний шлях
|
|
18
|
+
* @returns {'js' | 'jsx' | 'ts' | 'tsx'}
|
|
19
|
+
*/
|
|
20
|
+
function langFromPath(filePath) {
|
|
21
|
+
const lower = filePath.toLowerCase()
|
|
22
|
+
if (lower.endsWith('.tsx')) {
|
|
23
|
+
return 'tsx'
|
|
24
|
+
}
|
|
25
|
+
if (lower.endsWith('.ts') || lower.endsWith('.mts') || lower.endsWith('.cts')) {
|
|
26
|
+
return 'ts'
|
|
27
|
+
}
|
|
28
|
+
if (lower.endsWith('.jsx')) {
|
|
29
|
+
return 'jsx'
|
|
30
|
+
}
|
|
31
|
+
return 'js'
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Віртуальний шлях для парсера: SFC розбираємо як TypeScript.
|
|
36
|
+
* @param {string} relativePath відносний шлях до файлу
|
|
37
|
+
* @returns {string}
|
|
38
|
+
*/
|
|
39
|
+
function virtualPathForParse(relativePath) {
|
|
40
|
+
if (relativePath.endsWith('.vue')) {
|
|
41
|
+
return relativePath.replace(/\.vue$/u, '.ts')
|
|
42
|
+
}
|
|
43
|
+
return relativePath
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Чи містить AST хоча б один `gql` tagged template.
|
|
48
|
+
* @param {unknown} node корінь або вузол AST
|
|
49
|
+
* @returns {boolean}
|
|
50
|
+
*/
|
|
51
|
+
function astContainsGqlTag(node) {
|
|
52
|
+
if (node === null || node === undefined) {
|
|
53
|
+
return false
|
|
54
|
+
}
|
|
55
|
+
if (typeof node !== 'object') {
|
|
56
|
+
return false
|
|
57
|
+
}
|
|
58
|
+
if (Array.isArray(node)) {
|
|
59
|
+
return node.some(astContainsGqlTag)
|
|
60
|
+
}
|
|
61
|
+
if (node.type === 'TaggedTemplateExpression') {
|
|
62
|
+
const tag = node.tag
|
|
63
|
+
if (tag?.type === 'Identifier' && tag.name === 'gql') {
|
|
64
|
+
return true
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
for (const key of Object.keys(node)) {
|
|
68
|
+
if (key === 'loc' || key === 'range') {
|
|
69
|
+
continue
|
|
70
|
+
}
|
|
71
|
+
if (astContainsGqlTag(node[key])) {
|
|
72
|
+
return true
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return false
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Перевіряє один файл: є у скрипті (або у всьому не-vue) tagged template з тегом **`gql`**.
|
|
80
|
+
* @param {string} content сирий вміст файлу
|
|
81
|
+
* @param {string} relativePath відносний шлях (posix)
|
|
82
|
+
* @returns {boolean} true, якщо знайдено `gql`…``
|
|
83
|
+
*/
|
|
84
|
+
export function sourceFileHasGqlTaggedTemplate(content, relativePath) {
|
|
85
|
+
const scan = contentForVueImportScan(content, relativePath)
|
|
86
|
+
const pathForLang = virtualPathForParse(relativePath)
|
|
87
|
+
const lang = langFromPath(pathForLang)
|
|
88
|
+
try {
|
|
89
|
+
const result = parseSync(pathForLang, scan, { lang, sourceType: 'module' })
|
|
90
|
+
if (result.errors?.length) {
|
|
91
|
+
return false
|
|
92
|
+
}
|
|
93
|
+
return astContainsGqlTag(result.program)
|
|
94
|
+
} catch {
|
|
95
|
+
return false
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Чи підлягає файл скануванню за розширенням (узгоджено з vue-import scan).
|
|
101
|
+
* @param {string} relativePath відносний шлях
|
|
102
|
+
* @returns {boolean}
|
|
103
|
+
*/
|
|
104
|
+
export function isGqlScanSourceFile(relativePath) {
|
|
105
|
+
return isVueImportScanSourceFile(relativePath)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Чи пропустити файл (декларації, auto-imports) — ті самі критерії, що для vue-import scan.
|
|
110
|
+
* @param {string} relativePosix шлях з posix-слешами
|
|
111
|
+
* @returns {boolean}
|
|
112
|
+
*/
|
|
113
|
+
export function shouldSkipFileForGqlScan(relativePosix) {
|
|
114
|
+
return shouldSkipFileForVueImportScan(relativePosix)
|
|
115
|
+
}
|