@flagshark/core 1.3.0 → 1.3.1
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/README.md +100 -18
- package/dist/detection/detectors/go.d.ts +2 -2
- package/dist/detection/detectors/go.d.ts.map +1 -1
- package/dist/detection/detectors/javascript.d.ts +2 -2
- package/dist/detection/detectors/javascript.d.ts.map +1 -1
- package/dist/detection/detectors/python.d.ts +2 -2
- package/dist/detection/detectors/python.d.ts.map +1 -1
- package/dist/detection/detectors/typescript.d.ts +2 -2
- package/dist/detection/detectors/typescript.d.ts.map +1 -1
- package/dist/detection/index.d.ts +1 -1
- package/dist/detection/index.d.ts.map +1 -1
- package/dist/detection/interface.d.ts +2 -0
- package/dist/detection/interface.d.ts.map +1 -1
- package/dist/detection/tree-sitter/engine.d.ts.map +1 -1
- package/dist/detection/tree-sitter/engine.js +1 -12
- package/dist/detection/tree-sitter/engine.js.map +1 -1
- package/package.json +1 -1
- package/dist/detection/tree-sitter/query-builder.d.ts +0 -3
- package/dist/detection/tree-sitter/query-builder.d.ts.map +0 -1
- package/dist/detection/tree-sitter/query-builder.js +0 -7
- package/dist/detection/tree-sitter/query-builder.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @flagshark/core
|
|
2
2
|
|
|
3
|
-
The detection engine behind [FlagShark](https://github.com/FlagShark/flagshark) — finds feature flag references across 13 languages and
|
|
3
|
+
The detection engine behind [FlagShark](https://github.com/FlagShark/flagshark) — finds feature flag references across 13 languages and 13 providers, and identifies stale flags via git blame.
|
|
4
4
|
|
|
5
|
-
This is the **library**.
|
|
5
|
+
This is the **library**. For a CLI or GitHub Action, install [`flagshark`](https://www.npmjs.com/package/flagshark) instead.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -25,18 +25,26 @@ console.log(`Health score: ${result.healthScore}/100`)
|
|
|
25
25
|
console.log(`Languages: ${Object.keys(result.languageBreakdown).join(', ')}`)
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
## Detection
|
|
29
|
+
|
|
30
|
+
For tier-1 languages (TypeScript, JavaScript, Go, Python), detection uses [tree-sitter](https://tree-sitter.github.io/) (via WASM) to parse files into a real AST. That eliminates the false-positive class where regex matched flag-shaped strings inside comments, string literals, or unrelated call expressions. It also handles multi-line calls and resolves const-bound flag keys (`const FLAG = 'X'; client.variation(FLAG, …)`) in TS/JS.
|
|
31
|
+
|
|
32
|
+
The remaining 9 languages currently use regex-based detection; each migrates to tree-sitter in future releases (no API break).
|
|
33
|
+
|
|
34
|
+
The engine is a runtime concern, not a public API surface. Consumers calling `scanRepo()` or `createDefaultRegistry()` get the right engine per-language automatically. Override per-detector if needed (see below).
|
|
35
|
+
|
|
28
36
|
## API
|
|
29
37
|
|
|
30
38
|
### `scanRepo(options) → Promise<ScanRepoResult>`
|
|
31
39
|
|
|
32
|
-
Top-level orchestrator. Walks a checked-out repository, detects flags,
|
|
40
|
+
Top-level orchestrator. Walks a checked-out repository, detects flags, runs staleness analysis, and returns a summary.
|
|
33
41
|
|
|
34
42
|
```ts
|
|
35
43
|
interface ScanRepoOptions {
|
|
36
44
|
/** Absolute path to the repository being scanned. */
|
|
37
45
|
cwd: string
|
|
38
46
|
|
|
39
|
-
/** Staleness threshold in months.
|
|
47
|
+
/** Staleness threshold in months. Overridden by `config.threshold` if config is supplied. */
|
|
40
48
|
threshold?: number
|
|
41
49
|
|
|
42
50
|
/** If set, only scan files changed since this git ref (e.g. `origin/main`). */
|
|
@@ -48,20 +56,85 @@ interface ScanRepoOptions {
|
|
|
48
56
|
|
|
49
57
|
/** Optional `{ debug, info, warn, error }` logger. Defaults to no-op. */
|
|
50
58
|
logger?: ScanLogger
|
|
59
|
+
|
|
60
|
+
/** Explicit FlagsharkConfig. If undefined, scanRepo auto-discovers
|
|
61
|
+
* `.flagshark.yml` walking upward from `cwd`. */
|
|
62
|
+
config?: FlagsharkConfig
|
|
63
|
+
|
|
64
|
+
/** Skip `.flagshark.yml` discovery entirely. */
|
|
65
|
+
noConfig?: boolean
|
|
66
|
+
|
|
67
|
+
/** Skip `.flagsharkignore` discovery entirely. */
|
|
68
|
+
noIgnoreFile?: boolean
|
|
69
|
+
|
|
70
|
+
/** Populate `result.excludedPaths` with the full list of skipped file paths.
|
|
71
|
+
* Off by default — counts only. */
|
|
72
|
+
collectExcludedPaths?: boolean
|
|
51
73
|
}
|
|
52
74
|
|
|
53
75
|
interface ScanRepoResult {
|
|
54
76
|
totalFlags: number
|
|
55
|
-
filesScanned: number
|
|
56
77
|
staleFlags: StaleFlag[]
|
|
57
78
|
detectedProviders: string[]
|
|
58
79
|
languageBreakdown: Record<string, number>
|
|
59
|
-
healthScore: number
|
|
60
|
-
scanDuration: number
|
|
80
|
+
healthScore: number // 0–100
|
|
81
|
+
scanDuration: number // ms
|
|
82
|
+
excludedCount?: number // files skipped by config + .flagsharkignore
|
|
83
|
+
excludedPaths?: string[] // set when collectExcludedPaths: true
|
|
84
|
+
effectiveExcludes?: EffectiveRules // for debug/verbose output
|
|
61
85
|
}
|
|
62
86
|
```
|
|
63
87
|
|
|
64
|
-
`scanRepo` walks the local filesystem. If you can't run a git checkout (e.g., serverless function reading from an API), use the lower-level primitives below.
|
|
88
|
+
`scanRepo` walks the local filesystem. If you can't run a git checkout (e.g., a serverless function reading from an API), use the lower-level primitives below.
|
|
89
|
+
|
|
90
|
+
### Config module
|
|
91
|
+
|
|
92
|
+
The same config used by the CLI is exported as a building block:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import {
|
|
96
|
+
buildDefaultConfig,
|
|
97
|
+
loadConfigFile,
|
|
98
|
+
loadIgnoreFile,
|
|
99
|
+
buildExcluder,
|
|
100
|
+
expandPresets,
|
|
101
|
+
PRESETS,
|
|
102
|
+
FlagsharkConfigSchema,
|
|
103
|
+
type FlagsharkConfig,
|
|
104
|
+
} from '@flagshark/core'
|
|
105
|
+
|
|
106
|
+
// Load a .flagshark.yml from disk (validated via zod)
|
|
107
|
+
const loaded = await loadConfigFile('/path/to/repo')
|
|
108
|
+
const config = loaded?.config ?? buildDefaultConfig()
|
|
109
|
+
|
|
110
|
+
// Load a .flagsharkignore (separate file at repo root)
|
|
111
|
+
const ignoreFile = await loadIgnoreFile('/path/to/repo')
|
|
112
|
+
|
|
113
|
+
// Build a unified excluder from all sources
|
|
114
|
+
const excluder = buildExcluder({
|
|
115
|
+
config,
|
|
116
|
+
ignoreFilePatterns: ignoreFile?.patterns ?? [],
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
// Use it directly:
|
|
120
|
+
excluder.shouldExclude('examples/demo.ts') // true
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The schema accepts:
|
|
124
|
+
|
|
125
|
+
```yaml
|
|
126
|
+
threshold: 6
|
|
127
|
+
excludes:
|
|
128
|
+
paths: [] # gitignore-style globs
|
|
129
|
+
files: [] # same — split is purely organizational
|
|
130
|
+
presets: [] # ['test-files', 'snapshots', 'examples', 'stories', 'fixtures', 'generated']
|
|
131
|
+
suppress:
|
|
132
|
+
flags: [] # flag-name globs (post-detection filter)
|
|
133
|
+
paths:
|
|
134
|
+
- match: 'src/critical/**'
|
|
135
|
+
threshold: 3
|
|
136
|
+
providers: [] # custom provider definitions (see Custom Detectors)
|
|
137
|
+
```
|
|
65
138
|
|
|
66
139
|
### Lower-level primitives
|
|
67
140
|
|
|
@@ -71,7 +144,7 @@ For consumers that fetch file contents elsewhere (GitHub API, S3, in-memory, etc
|
|
|
71
144
|
import { createDefaultRegistry, PolyglotAnalyzer } from '@flagshark/core'
|
|
72
145
|
|
|
73
146
|
const registry = createDefaultRegistry() // 13 detectors pre-registered
|
|
74
|
-
const analyzer = new PolyglotAnalyzer(registry)
|
|
147
|
+
const analyzer = new PolyglotAnalyzer(registry, logger)
|
|
75
148
|
|
|
76
149
|
// `files` is a Map<filePath, content>
|
|
77
150
|
const result = await analyzer.analyzeFiles(files)
|
|
@@ -101,34 +174,43 @@ const registry = createDefaultRegistry()
|
|
|
101
174
|
registry.register(new MyCustomDetector())
|
|
102
175
|
```
|
|
103
176
|
|
|
104
|
-
Or import individual detectors and compose your own registry:
|
|
177
|
+
Or import individual detectors and compose your own registry. Each tier-1 detector accepts `{ engine: 'regex' | 'tree-sitter' }`:
|
|
105
178
|
|
|
106
179
|
```ts
|
|
107
|
-
import {
|
|
180
|
+
import {
|
|
181
|
+
LanguageRegistry,
|
|
182
|
+
TypeScriptDetector,
|
|
183
|
+
GoDetector,
|
|
184
|
+
type DetectorEngine,
|
|
185
|
+
} from '@flagshark/core'
|
|
108
186
|
|
|
109
187
|
const registry = new LanguageRegistry()
|
|
110
|
-
registry.register(new
|
|
111
|
-
registry.register(new
|
|
188
|
+
registry.register(new TypeScriptDetector({ engine: 'tree-sitter' }))
|
|
189
|
+
registry.register(new GoDetector({ engine: 'regex' })) // opt back to regex
|
|
112
190
|
```
|
|
113
191
|
|
|
114
192
|
## Supported languages
|
|
115
193
|
|
|
116
|
-
TypeScript
|
|
194
|
+
TypeScript, JavaScript, Go, Python, Java, Kotlin, Swift, Ruby, C#, PHP, Rust, C/C++, Objective-C.
|
|
117
195
|
|
|
118
196
|
## Supported providers
|
|
119
197
|
|
|
120
|
-
Auto-detected from imports — no configuration needed:
|
|
198
|
+
Auto-detected from imports — no configuration needed:
|
|
199
|
+
|
|
200
|
+
LaunchDarkly · Unleash · Flipt · Split.io · PostHog · Flagsmith · ConfigCat · Statsig · GrowthBook · DevCycle · Eppo · Optimizely · plus generic custom-flag patterns.
|
|
121
201
|
|
|
122
202
|
## How detection works
|
|
123
203
|
|
|
124
|
-
|
|
204
|
+
FlagShark only scans files that actually import a flag SDK. A function called `isEnabled()` in a file that doesn't import LaunchDarkly/Unleash/etc. won't be flagged — this prevents false positives from generic identifier names.
|
|
205
|
+
|
|
206
|
+
Once a file qualifies, the engine (tree-sitter for tier-1, regex for the rest) walks call expressions and extracts the flag-key argument at the configured position for each provider's method signatures. Provider attribution and source location come along automatically.
|
|
125
207
|
|
|
126
208
|
## How staleness works
|
|
127
209
|
|
|
128
210
|
A flag is marked stale if **any** signal fires:
|
|
129
211
|
|
|
130
|
-
1.
|
|
131
|
-
2.
|
|
212
|
+
1. **`age`** — `git blame` shows the flag's line was last modified more than `threshold` months ago.
|
|
213
|
+
2. **`low-usage`** — The flag name appears in only one file across the repo, suggesting a completed rollout.
|
|
132
214
|
|
|
133
215
|
## License
|
|
134
216
|
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Ported from Go: internal/languages/golang/detector.go
|
|
4
4
|
*/
|
|
5
5
|
import type { FeatureFlag } from '../feature-flag.js';
|
|
6
|
-
import type { FeatureFlagProvider, Language, LanguageDetector } from '../interface.js';
|
|
7
|
-
export type DetectorEngine
|
|
6
|
+
import type { DetectorEngine, FeatureFlagProvider, Language, LanguageDetector } from '../interface.js';
|
|
7
|
+
export type { DetectorEngine };
|
|
8
8
|
export interface GoDetectorOptions {
|
|
9
9
|
providers?: FeatureFlagProvider[];
|
|
10
10
|
engine?: DetectorEngine;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"go.d.ts","sourceRoot":"","sources":["../../../src/detection/detectors/go.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"go.d.ts","sourceRoot":"","sources":["../../../src/detection/detectors/go.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAEtG,YAAY,EAAE,cAAc,EAAE,CAAA;AAE9B,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,mBAAmB,EAAE,CAAA;IACjC,MAAM,CAAC,EAAE,cAAc,CAAA;CACxB;AAED,qBAAa,UAAW,YAAW,gBAAgB;IACjD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAuB;IACjD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;gBAE3B,IAAI,GAAE,iBAAsB;IAKxC,QAAQ,IAAI,QAAQ;IAIpB,cAAc,IAAI,MAAM,EAAE;IAI1B,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAIvC,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAOtF,YAAY,IAAI,mBAAmB,EAAE;CAGtC;AAED,wBAAgB,kBAAkB,IAAI,mBAAmB,EAAE,CAkS1D"}
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* but reports the language as "javascript".
|
|
6
6
|
*/
|
|
7
7
|
import type { FeatureFlag } from '../feature-flag.js';
|
|
8
|
-
import type { FeatureFlagProvider, Language, LanguageDetector } from '../interface.js';
|
|
9
|
-
export type DetectorEngine
|
|
8
|
+
import type { DetectorEngine, FeatureFlagProvider, Language, LanguageDetector } from '../interface.js';
|
|
9
|
+
export type { DetectorEngine };
|
|
10
10
|
export interface JavaScriptDetectorOptions {
|
|
11
11
|
providers?: FeatureFlagProvider[];
|
|
12
12
|
engine?: DetectorEngine;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"javascript.d.ts","sourceRoot":"","sources":["../../../src/detection/detectors/javascript.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"javascript.d.ts","sourceRoot":"","sources":["../../../src/detection/detectors/javascript.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAEtG,YAAY,EAAE,cAAc,EAAE,CAAA;AAE9B,MAAM,WAAW,yBAAyB;IACxC,SAAS,CAAC,EAAE,mBAAmB,EAAE,CAAA;IACjC,MAAM,CAAC,EAAE,cAAc,CAAA;CACxB;AAED,qBAAa,kBAAmB,YAAW,gBAAgB;IACzD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAuB;IACjD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;gBAE3B,IAAI,GAAE,yBAA8B;IAKhD,QAAQ,IAAI,QAAQ;IAIpB,cAAc,IAAI,MAAM,EAAE;IAI1B,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAKvC,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAOtF,YAAY,IAAI,mBAAmB,EAAE;CAGtC"}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Ported from Go: internal/languages/python/detector.go
|
|
4
4
|
*/
|
|
5
5
|
import type { FeatureFlag } from '../feature-flag.js';
|
|
6
|
-
import type { FeatureFlagProvider, Language, LanguageDetector } from '../interface.js';
|
|
7
|
-
export type DetectorEngine
|
|
6
|
+
import type { DetectorEngine, FeatureFlagProvider, Language, LanguageDetector } from '../interface.js';
|
|
7
|
+
export type { DetectorEngine };
|
|
8
8
|
export interface PythonDetectorOptions {
|
|
9
9
|
providers?: FeatureFlagProvider[];
|
|
10
10
|
engine?: DetectorEngine;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"python.d.ts","sourceRoot":"","sources":["../../../src/detection/detectors/python.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"python.d.ts","sourceRoot":"","sources":["../../../src/detection/detectors/python.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAEtG,YAAY,EAAE,cAAc,EAAE,CAAA;AAE9B,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,mBAAmB,EAAE,CAAA;IACjC,MAAM,CAAC,EAAE,cAAc,CAAA;CACxB;AAED,qBAAa,cAAe,YAAW,gBAAgB;IACrD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAuB;IACjD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;gBAE3B,IAAI,GAAE,qBAA0B;IAK5C,QAAQ,IAAI,QAAQ;IAIpB,cAAc,IAAI,MAAM,EAAE;IAI1B,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAKvC,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAOtF,YAAY,IAAI,mBAAmB,EAAE;CAGtC;AAED,wBAAgB,sBAAsB,IAAI,mBAAmB,EAAE,CA8P9D"}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Ported from Go: internal/languages/typescript/detector.go
|
|
4
4
|
*/
|
|
5
5
|
import type { FeatureFlag } from '../feature-flag.js';
|
|
6
|
-
import type { FeatureFlagProvider, Language, LanguageDetector } from '../interface.js';
|
|
7
|
-
export type DetectorEngine
|
|
6
|
+
import type { DetectorEngine, FeatureFlagProvider, Language, LanguageDetector } from '../interface.js';
|
|
7
|
+
export type { DetectorEngine };
|
|
8
8
|
export interface TypeScriptDetectorOptions {
|
|
9
9
|
providers?: FeatureFlagProvider[];
|
|
10
10
|
engine?: DetectorEngine;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typescript.d.ts","sourceRoot":"","sources":["../../../src/detection/detectors/typescript.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"typescript.d.ts","sourceRoot":"","sources":["../../../src/detection/detectors/typescript.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAEtG,YAAY,EAAE,cAAc,EAAE,CAAA;AAE9B,MAAM,WAAW,yBAAyB;IACxC,SAAS,CAAC,EAAE,mBAAmB,EAAE,CAAA;IACjC,MAAM,CAAC,EAAE,cAAc,CAAA;CACxB;AAED,qBAAa,kBAAmB,YAAW,gBAAgB;IACzD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAuB;IACjD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;gBAE3B,IAAI,GAAE,yBAA8B;IAKhD,QAAQ,IAAI,QAAQ;IAIpB,cAAc,IAAI,MAAM,EAAE;IAI1B,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAKvC,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAOtF,YAAY,IAAI,mBAAmB,EAAE;CAGtC;AAED,wBAAgB,0BAA0B,IAAI,mBAAmB,EAAE,CAgUlE"}
|
|
@@ -18,7 +18,7 @@ export { convertConfigProviders, languageToConfigLanguage, loadProvidersForLangu
|
|
|
18
18
|
* Non-tier-1 detectors use regex (the per-detector default).
|
|
19
19
|
*/
|
|
20
20
|
export declare function createDefaultRegistry(): LanguageRegistry;
|
|
21
|
-
import type { DetectorEngine } from './
|
|
21
|
+
import type { DetectorEngine } from './interface.js';
|
|
22
22
|
/**
|
|
23
23
|
* Build a registry where every tier-1 detector uses the given engine.
|
|
24
24
|
* Used by the CLI's --engine flag and by the cross-engine smoke test.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/detection/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAeH,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAGhD,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,YAAY,EACV,QAAQ,EACR,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EACZ,eAAe,GAChB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAG5D,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AAG1F,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AACzE,YAAY,EACV,YAAY,EACZ,gBAAgB,IAAI,wBAAwB,EAC5C,kBAAkB,EAClB,kBAAkB,EAClB,wBAAwB,EACxB,wBAAwB,EACxB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,QAAQ,IAAI,gBAAgB,GAC7B,MAAM,wBAAwB,CAAA;AAG/B,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,YAAY,EACZ,cAAc,EACd,aAAa,EACb,YAAY,EACZ,cAAc,EACd,WAAW,EACX,YAAY,EACZ,WAAW,EACX,kBAAkB,GACnB,MAAM,sBAAsB,CAAA;AAG7B,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,qBAAqB,EACrB,cAAc,EACd,sBAAsB,EACtB,YAAY,EACZ,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,cAAc,CAAA;AAGrB,OAAO,EACL,sBAAsB,EACtB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,qBAAqB,CAAA;AAE5B;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,gBAAgB,CAiBxD;AAED,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/detection/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAeH,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAGhD,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,YAAY,EACV,QAAQ,EACR,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EACZ,eAAe,GAChB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAG5D,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AAG1F,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AACzE,YAAY,EACV,YAAY,EACZ,gBAAgB,IAAI,wBAAwB,EAC5C,kBAAkB,EAClB,kBAAkB,EAClB,wBAAwB,EACxB,wBAAwB,EACxB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,QAAQ,IAAI,gBAAgB,GAC7B,MAAM,wBAAwB,CAAA;AAG/B,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,YAAY,EACZ,cAAc,EACd,aAAa,EACb,YAAY,EACZ,cAAc,EACd,WAAW,EACX,YAAY,EACZ,WAAW,EACX,kBAAkB,GACnB,MAAM,sBAAsB,CAAA;AAG7B,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,qBAAqB,EACrB,cAAc,EACd,sBAAsB,EACtB,YAAY,EACZ,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,cAAc,CAAA;AAGrB,OAAO,EACL,sBAAsB,EACtB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,qBAAqB,CAAA;AAE5B;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,gBAAgB,CAiBxD;AAED,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAEpD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,cAAc,GAAG,gBAAgB,CAiBjF"}
|
|
@@ -73,4 +73,6 @@ export interface DetectionResult {
|
|
|
73
73
|
language: Language;
|
|
74
74
|
metadata?: Record<string, unknown>;
|
|
75
75
|
}
|
|
76
|
+
/** Which detection engine to use for tier-1 language detectors. */
|
|
77
|
+
export type DetectorEngine = 'regex' | 'tree-sitter';
|
|
76
78
|
//# sourceMappingURL=interface.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/detection/interface.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAEpD,kDAAkD;AAClD,MAAM,MAAM,QAAQ,GAChB,IAAI,GACJ,YAAY,GACZ,YAAY,GACZ,QAAQ,GACR,MAAM,GACN,QAAQ,GACR,OAAO,GACP,MAAM,GACN,QAAQ,GACR,KAAK,GACL,MAAM,GACN,KAAK,GACL,MAAM,CAAA;AAEV,wDAAwD;AACxD,eAAO,MAAM,SAAS;iBACR,QAAQ;yBACQ,QAAQ;yBACR,QAAQ;qBAChB,QAAQ;mBACZ,QAAQ;qBACJ,QAAQ;oBACV,QAAQ;mBACV,QAAQ;qBACJ,QAAQ;kBACd,QAAQ;mBACN,QAAQ;kBACV,QAAQ;yBACA,QAAQ;CACtB,CAAA;AAEV,iEAAiE;AACjE,MAAM,WAAW,YAAY;IAC3B,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAA;IACZ,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,mEAAmE;IACnE,YAAY,EAAE,MAAM,CAAA;IACpB,gDAAgD;IAChD,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CACpB;AAED,yEAAyE;AACzE,MAAM,WAAW,mBAAmB;IAClC,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAA;IACZ,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,6CAA6C;IAC7C,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,wBAAwB;IACxB,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,iCAAiC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qDAAqD;IACrD,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,MAAM,CAEtE;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,mDAAmD;IACnD,QAAQ,IAAI,QAAQ,CAAA;IAEpB,gFAAgF;IAChF,cAAc,IAAI,MAAM,EAAE,CAAA;IAE1B,sDAAsD;IACtD,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAA;IAEtF,yDAAyD;IACzD,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;IAEvC,qEAAqE;IACrE,YAAY,IAAI,mBAAmB,EAAE,CAAA;CACtC;AAED,+CAA+C;AAC/C,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,WAAW,EAAE,CAAA;IACpB,QAAQ,EAAE,QAAQ,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACnC"}
|
|
1
|
+
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/detection/interface.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAEpD,kDAAkD;AAClD,MAAM,MAAM,QAAQ,GAChB,IAAI,GACJ,YAAY,GACZ,YAAY,GACZ,QAAQ,GACR,MAAM,GACN,QAAQ,GACR,OAAO,GACP,MAAM,GACN,QAAQ,GACR,KAAK,GACL,MAAM,GACN,KAAK,GACL,MAAM,CAAA;AAEV,wDAAwD;AACxD,eAAO,MAAM,SAAS;iBACR,QAAQ;yBACQ,QAAQ;yBACR,QAAQ;qBAChB,QAAQ;mBACZ,QAAQ;qBACJ,QAAQ;oBACV,QAAQ;mBACV,QAAQ;qBACJ,QAAQ;kBACd,QAAQ;mBACN,QAAQ;kBACV,QAAQ;yBACA,QAAQ;CACtB,CAAA;AAEV,iEAAiE;AACjE,MAAM,WAAW,YAAY;IAC3B,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAA;IACZ,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,mEAAmE;IACnE,YAAY,EAAE,MAAM,CAAA;IACpB,gDAAgD;IAChD,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CACpB;AAED,yEAAyE;AACzE,MAAM,WAAW,mBAAmB;IAClC,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAA;IACZ,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,6CAA6C;IAC7C,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,wBAAwB;IACxB,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,iCAAiC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qDAAqD;IACrD,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,MAAM,CAEtE;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,mDAAmD;IACnD,QAAQ,IAAI,QAAQ,CAAA;IAEpB,gFAAgF;IAChF,cAAc,IAAI,MAAM,EAAE,CAAA;IAE1B,sDAAsD;IACtD,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAA;IAEtF,yDAAyD;IACzD,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;IAEvC,qEAAqE;IACrE,YAAY,IAAI,mBAAmB,EAAE,CAAA;CACtC;AAED,+CAA+C;AAC/C,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,WAAW,EAAE,CAAA;IACpB,QAAQ,EAAE,QAAQ,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACnC;AAED,mEAAmE;AACnE,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,aAAa,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/detection/tree-sitter/engine.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAgB,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/detection/tree-sitter/engine.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAgB,MAAM,iBAAiB,CAAA;AAMlF;;;;;;GAMG;AACH,wBAAsB,yBAAyB,CAC7C,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,mBAAmB,EAAE,GAC/B,OAAO,CAAC,WAAW,EAAE,CAAC,CA2DxB"}
|
|
@@ -1,19 +1,8 @@
|
|
|
1
|
-
import { deduplicateFlags } from '../helpers.js';
|
|
1
|
+
import { deduplicateFlags, isValidFlagKey } from '../helpers.js';
|
|
2
2
|
import { getImportPattern } from '../interface.js';
|
|
3
3
|
import { getParser } from './parser-cache.js';
|
|
4
4
|
import { getQuery, iterateCalls, getArgument, extractStringLiteral } from './query-runner.js';
|
|
5
5
|
import { resolveConstStringTS } from './const-resolver.js';
|
|
6
|
-
const FLAG_KEY_MAX_LENGTH = 256;
|
|
7
|
-
const INVALID_PREFIXES = ['http://', 'https://', 'file://', '/'];
|
|
8
|
-
function isValidFlagKey(key) {
|
|
9
|
-
if (key.length === 0 || key.length > FLAG_KEY_MAX_LENGTH)
|
|
10
|
-
return false;
|
|
11
|
-
for (const prefix of INVALID_PREFIXES) {
|
|
12
|
-
if (key.startsWith(prefix))
|
|
13
|
-
return false;
|
|
14
|
-
}
|
|
15
|
-
return true;
|
|
16
|
-
}
|
|
17
6
|
/**
|
|
18
7
|
* Detect feature flags via tree-sitter. Mirrors detectFlagsWithRegex's contract.
|
|
19
8
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/detection/tree-sitter/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/detection/tree-sitter/engine.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"query-builder.d.ts","sourceRoot":"","sources":["../../../src/detection/tree-sitter/query-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAI/C,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAI3D"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { loadQueryText } from './query-runner.js';
|
|
2
|
-
export function buildMethodCallQuery(lang) {
|
|
3
|
-
// Today: just return the static query for the language.
|
|
4
|
-
// Future: synthesize per-method-set queries when we want predicate filtering inside the .scm.
|
|
5
|
-
return loadQueryText(lang);
|
|
6
|
-
}
|
|
7
|
-
//# sourceMappingURL=query-builder.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"query-builder.js","sourceRoot":"","sources":["../../../src/detection/tree-sitter/query-builder.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEjD,MAAM,UAAU,oBAAoB,CAAC,IAAc;IACjD,wDAAwD;IACxD,8FAA8F;IAC9F,OAAO,aAAa,CAAC,IAAI,CAAC,CAAA;AAC5B,CAAC"}
|