i18next-cli 1.24.12 → 1.24.14
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/dist/cjs/cli.js +1 -1
- package/dist/cjs/extractor/parsers/expression-resolver.js +1 -1
- package/dist/esm/cli.js +1 -1
- package/dist/esm/extractor/parsers/expression-resolver.js +1 -1
- package/package.json +6 -6
- package/types/cli.d.ts +3 -1
- package/types/cli.d.ts.map +1 -1
- package/types/extractor/parsers/expression-resolver.d.ts.map +1 -1
- package/CHANGELOG.md +0 -595
- package/src/cli.ts +0 -283
- package/src/config.ts +0 -215
- package/src/extractor/core/ast-visitors.ts +0 -259
- package/src/extractor/core/extractor.ts +0 -250
- package/src/extractor/core/key-finder.ts +0 -142
- package/src/extractor/core/translation-manager.ts +0 -750
- package/src/extractor/index.ts +0 -7
- package/src/extractor/parsers/ast-utils.ts +0 -87
- package/src/extractor/parsers/call-expression-handler.ts +0 -793
- package/src/extractor/parsers/comment-parser.ts +0 -424
- package/src/extractor/parsers/expression-resolver.ts +0 -353
- package/src/extractor/parsers/jsx-handler.ts +0 -488
- package/src/extractor/parsers/jsx-parser.ts +0 -1463
- package/src/extractor/parsers/scope-manager.ts +0 -445
- package/src/extractor/plugin-manager.ts +0 -116
- package/src/extractor.ts +0 -15
- package/src/heuristic-config.ts +0 -92
- package/src/index.ts +0 -22
- package/src/init.ts +0 -175
- package/src/linter.ts +0 -345
- package/src/locize.ts +0 -263
- package/src/migrator.ts +0 -208
- package/src/rename-key.ts +0 -398
- package/src/status.ts +0 -380
- package/src/syncer.ts +0 -133
- package/src/types-generator.ts +0 -139
- package/src/types.ts +0 -577
- package/src/utils/default-value.ts +0 -45
- package/src/utils/file-utils.ts +0 -167
- package/src/utils/funnel-msg-tracker.ts +0 -84
- package/src/utils/logger.ts +0 -36
- package/src/utils/nested-object.ts +0 -135
- package/src/utils/validation.ts +0 -72
|
@@ -1,424 +0,0 @@
|
|
|
1
|
-
import type { PluginContext, I18nextToolkitConfig } from '../../types'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Extracts translation keys from comments in source code using regex patterns.
|
|
5
|
-
* Supports extraction from single-line (//) and multi-line comments.
|
|
6
|
-
*
|
|
7
|
-
* @param code - The source code to analyze
|
|
8
|
-
* @param pluginContext - Context object with helper methods to add found keys
|
|
9
|
-
* @param config - Configuration object containing extraction settings
|
|
10
|
-
* @param scopeResolver - Function to resolve scope information for variables (optional)
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```typescript
|
|
14
|
-
* const code = `
|
|
15
|
-
* // t('user.name', 'User Name')
|
|
16
|
-
* /* t('app.title', { defaultValue: 'My App', ns: 'common' }) *\/
|
|
17
|
-
* `
|
|
18
|
-
*
|
|
19
|
-
* const context = createPluginContext(allKeys)
|
|
20
|
-
* extractKeysFromComments(code, context, config, scopeResolver)
|
|
21
|
-
* // Extracts: user.name and app.title with their respective settings
|
|
22
|
-
* ```
|
|
23
|
-
*/
|
|
24
|
-
export function extractKeysFromComments (
|
|
25
|
-
code: string,
|
|
26
|
-
pluginContext: PluginContext,
|
|
27
|
-
config: I18nextToolkitConfig,
|
|
28
|
-
scopeResolver?: (varName: string) => { defaultNs?: string; keyPrefix?: string } | undefined
|
|
29
|
-
): void {
|
|
30
|
-
// Hardcode the function name to 't' to prevent parsing other functions like 'test()'.
|
|
31
|
-
const functionNameToFind = 't'
|
|
32
|
-
|
|
33
|
-
// Use a reliable word boundary (\b) to match 't(...)' but not 'http.get(...)'.
|
|
34
|
-
const keyRegex = new RegExp(`\\b${functionNameToFind}\\s*\\(\\s*(['"])([^'"]+)\\1`, 'g')
|
|
35
|
-
|
|
36
|
-
// Prepare preservePatterns for filtering
|
|
37
|
-
const rawPreservePatterns = config.extract.preservePatterns || []
|
|
38
|
-
const preservePatterns = rawPreservePatterns.map(globToRegex)
|
|
39
|
-
const nsSeparator = config.extract.nsSeparator ?? ':'
|
|
40
|
-
|
|
41
|
-
const matchesPreserve = (key: string, ns?: string) => {
|
|
42
|
-
// 1) regex-style matches (existing behavior)
|
|
43
|
-
if (preservePatterns.some(re => re.test(key))) return true
|
|
44
|
-
// 2) namespace:* style patterns => preserve entire namespace
|
|
45
|
-
for (const rp of rawPreservePatterns) {
|
|
46
|
-
if (typeof rp !== 'string') continue
|
|
47
|
-
if (rp.endsWith(`${nsSeparator}*`)) {
|
|
48
|
-
const nsPrefix = (typeof nsSeparator === 'string' && nsSeparator.length > 0)
|
|
49
|
-
? rp.slice(0, -(nsSeparator.length + 1))
|
|
50
|
-
: rp.slice(0, -1)
|
|
51
|
-
// support '*' as a wildcard namespace
|
|
52
|
-
if (nsPrefix === '*' || (ns && nsPrefix === ns)) return true
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return false
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const commentTexts = collectCommentTexts(code)
|
|
59
|
-
|
|
60
|
-
for (const text of commentTexts) {
|
|
61
|
-
let match: RegExpExecArray | null
|
|
62
|
-
while ((match = keyRegex.exec(text)) !== null) {
|
|
63
|
-
let key = match[2]
|
|
64
|
-
|
|
65
|
-
// Validate that the key is not empty or whitespace-only
|
|
66
|
-
if (!key || key.trim() === '') {
|
|
67
|
-
continue // Skip empty keys
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// We'll check preservePatterns after namespace resolution below
|
|
71
|
-
|
|
72
|
-
let ns: string | false | undefined
|
|
73
|
-
const remainder = text.slice(match.index + match[0].length)
|
|
74
|
-
|
|
75
|
-
const defaultValue = parseDefaultValueFromComment(remainder)
|
|
76
|
-
const context = parseContextFromComment(remainder)
|
|
77
|
-
const count = parseCountFromComment(remainder)
|
|
78
|
-
const ordinal = parseOrdinalFromComment(remainder)
|
|
79
|
-
|
|
80
|
-
// Check if key ends with _ordinal suffix (like in ast-visitors)
|
|
81
|
-
let isOrdinalByKey = false
|
|
82
|
-
const pluralSeparator = config.extract.pluralSeparator ?? '_'
|
|
83
|
-
if (key.endsWith(`${pluralSeparator}ordinal`)) {
|
|
84
|
-
isOrdinalByKey = true
|
|
85
|
-
// Normalize the key by stripping the suffix
|
|
86
|
-
key = key.slice(0, -(pluralSeparator.length + 7)) // Remove "_ordinal"
|
|
87
|
-
|
|
88
|
-
// Validate that the key is still not empty after normalization
|
|
89
|
-
if (!key || key.trim() === '') {
|
|
90
|
-
continue // Skip keys that become empty after normalization
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Re-check preservePatterns after key normalization (will check namespace-aware helper)
|
|
94
|
-
if (matchesPreserve(key, ns as string | undefined)) {
|
|
95
|
-
continue // Skip normalized keys that match preserve patterns
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const isOrdinal = ordinal === true || isOrdinalByKey
|
|
100
|
-
|
|
101
|
-
// 1. Check for namespace in options object first (e.g., { ns: 'common' })
|
|
102
|
-
ns = parseNsFromComment(remainder)
|
|
103
|
-
|
|
104
|
-
// 2. If not in options, check for separator in key (e.g., 'common:button.save')
|
|
105
|
-
const nsSeparator = config.extract.nsSeparator ?? ':'
|
|
106
|
-
if (!ns && nsSeparator && key.includes(nsSeparator)) {
|
|
107
|
-
const parts = key.split(nsSeparator)
|
|
108
|
-
ns = parts.shift()
|
|
109
|
-
key = parts.join(nsSeparator)
|
|
110
|
-
|
|
111
|
-
// Validate that the key didn't become empty after namespace removal
|
|
112
|
-
if (!key || key.trim() === '') {
|
|
113
|
-
continue // Skip keys that become empty after namespace removal
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Re-check preservePatterns after namespace processing (namespace-aware)
|
|
117
|
-
if (matchesPreserve(key, ns as string | undefined)) {
|
|
118
|
-
continue // Skip processed keys that match preserve patterns
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// 3. If no explicit namespace found, try to resolve from scope
|
|
123
|
-
// This allows commented t() calls to inherit namespace from useTranslation scope
|
|
124
|
-
if (!ns && scopeResolver) {
|
|
125
|
-
const scopeInfo = scopeResolver('t')
|
|
126
|
-
if (scopeInfo?.defaultNs) {
|
|
127
|
-
ns = scopeInfo.defaultNs
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Final preserve check for keys without prior namespace normalization
|
|
132
|
-
if (matchesPreserve(key, ns as string | undefined)) {
|
|
133
|
-
continue
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// 4. Final fallback to configured default namespace
|
|
137
|
-
if (!ns) ns = config.extract.defaultNS
|
|
138
|
-
|
|
139
|
-
// 5. Handle context and count combinations based on disablePlurals setting
|
|
140
|
-
if (config.extract.disablePlurals) {
|
|
141
|
-
// When plurals are disabled, ignore count for key generation
|
|
142
|
-
if (context) {
|
|
143
|
-
// Only generate context variants (no base key when context is static)
|
|
144
|
-
pluginContext.addKey({ key: `${key}_${context}`, ns, defaultValue: defaultValue ?? key })
|
|
145
|
-
} else {
|
|
146
|
-
// Simple key (ignore count)
|
|
147
|
-
pluginContext.addKey({ key, ns, defaultValue: defaultValue ?? key })
|
|
148
|
-
}
|
|
149
|
-
} else {
|
|
150
|
-
// Original plural handling logic when plurals are enabled
|
|
151
|
-
if (context && count) {
|
|
152
|
-
// Generate context+plural combinations
|
|
153
|
-
generateContextPluralKeys(key, defaultValue ?? key, ns, context, pluginContext, config, isOrdinal)
|
|
154
|
-
|
|
155
|
-
// Only generate base plural forms if generateBasePluralForms is not disabled
|
|
156
|
-
const shouldGenerateBaseForms = config.extract?.generateBasePluralForms !== false
|
|
157
|
-
if (shouldGenerateBaseForms) {
|
|
158
|
-
generatePluralKeys(key, defaultValue ?? key, ns, pluginContext, config, isOrdinal)
|
|
159
|
-
}
|
|
160
|
-
} else if (context) {
|
|
161
|
-
// Just context variants
|
|
162
|
-
pluginContext.addKey({ key, ns, defaultValue: defaultValue ?? key })
|
|
163
|
-
pluginContext.addKey({ key: `${key}_${context}`, ns, defaultValue: defaultValue ?? key })
|
|
164
|
-
} else if (count) {
|
|
165
|
-
// Just plural variants
|
|
166
|
-
generatePluralKeys(key, defaultValue ?? key, ns, pluginContext, config, isOrdinal)
|
|
167
|
-
} else {
|
|
168
|
-
// Simple key
|
|
169
|
-
pluginContext.addKey({ key, ns, defaultValue: defaultValue ?? key })
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Generates plural keys for a given base key
|
|
178
|
-
*/
|
|
179
|
-
function generatePluralKeys (
|
|
180
|
-
key: string,
|
|
181
|
-
defaultValue: string,
|
|
182
|
-
ns: string | false | undefined,
|
|
183
|
-
pluginContext: PluginContext,
|
|
184
|
-
config: I18nextToolkitConfig,
|
|
185
|
-
isOrdinal = false
|
|
186
|
-
): void {
|
|
187
|
-
try {
|
|
188
|
-
const type = isOrdinal ? 'ordinal' : 'cardinal'
|
|
189
|
-
|
|
190
|
-
// Generate plural forms for ALL target languages to ensure we have all necessary keys
|
|
191
|
-
const allPluralCategories = new Set<string>()
|
|
192
|
-
|
|
193
|
-
for (const locale of config.locales) {
|
|
194
|
-
try {
|
|
195
|
-
const pluralRules = new Intl.PluralRules(locale, { type })
|
|
196
|
-
const categories = pluralRules.resolvedOptions().pluralCategories
|
|
197
|
-
categories.forEach(cat => allPluralCategories.add(cat))
|
|
198
|
-
} catch (e) {
|
|
199
|
-
// If a locale is invalid, fall back to English rules
|
|
200
|
-
const englishRules = new Intl.PluralRules('en', { type })
|
|
201
|
-
const categories = englishRules.resolvedOptions().pluralCategories
|
|
202
|
-
categories.forEach(cat => allPluralCategories.add(cat))
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
const pluralCategories = Array.from(allPluralCategories).sort()
|
|
207
|
-
const pluralSeparator = config.extract.pluralSeparator ?? '_'
|
|
208
|
-
|
|
209
|
-
// If the only plural category is "other", prefer emitting the base key instead of "key_other"
|
|
210
|
-
if (pluralCategories.length === 1 && pluralCategories[0] === 'other') {
|
|
211
|
-
// Emit base key only
|
|
212
|
-
pluginContext.addKey({
|
|
213
|
-
key,
|
|
214
|
-
ns,
|
|
215
|
-
defaultValue,
|
|
216
|
-
hasCount: true
|
|
217
|
-
})
|
|
218
|
-
return
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// Generate keys for each plural category
|
|
222
|
-
for (const category of pluralCategories) {
|
|
223
|
-
const finalKey = isOrdinal
|
|
224
|
-
? `${key}${pluralSeparator}ordinal${pluralSeparator}${category}`
|
|
225
|
-
: `${key}${pluralSeparator}${category}`
|
|
226
|
-
|
|
227
|
-
pluginContext.addKey({
|
|
228
|
-
key: finalKey,
|
|
229
|
-
ns,
|
|
230
|
-
defaultValue,
|
|
231
|
-
hasCount: true,
|
|
232
|
-
isOrdinal
|
|
233
|
-
})
|
|
234
|
-
}
|
|
235
|
-
} catch (e) {
|
|
236
|
-
// Fallback if Intl API fails
|
|
237
|
-
pluginContext.addKey({ key, ns, defaultValue })
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* Generates context + plural combination keys
|
|
243
|
-
*/
|
|
244
|
-
function generateContextPluralKeys (
|
|
245
|
-
key: string,
|
|
246
|
-
defaultValue: string,
|
|
247
|
-
ns: string | false | undefined,
|
|
248
|
-
context: string,
|
|
249
|
-
pluginContext: PluginContext,
|
|
250
|
-
config: I18nextToolkitConfig,
|
|
251
|
-
isOrdinal = false
|
|
252
|
-
): void {
|
|
253
|
-
try {
|
|
254
|
-
const type = isOrdinal ? 'ordinal' : 'cardinal'
|
|
255
|
-
|
|
256
|
-
// Generate plural forms for ALL target languages to ensure we have all necessary keys
|
|
257
|
-
const allPluralCategories = new Set<string>()
|
|
258
|
-
|
|
259
|
-
for (const locale of config.locales) {
|
|
260
|
-
try {
|
|
261
|
-
const pluralRules = new Intl.PluralRules(locale, { type })
|
|
262
|
-
const categories = pluralRules.resolvedOptions().pluralCategories
|
|
263
|
-
categories.forEach(cat => allPluralCategories.add(cat))
|
|
264
|
-
} catch (e) {
|
|
265
|
-
// If a locale is invalid, fall back to English rules
|
|
266
|
-
const englishRules = new Intl.PluralRules(config.extract.primaryLanguage || 'en', { type })
|
|
267
|
-
const categories = englishRules.resolvedOptions().pluralCategories
|
|
268
|
-
categories.forEach(cat => allPluralCategories.add(cat))
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
const pluralCategories = Array.from(allPluralCategories).sort()
|
|
273
|
-
const pluralSeparator = config.extract.pluralSeparator ?? '_'
|
|
274
|
-
|
|
275
|
-
// Generate keys for each context + plural combination
|
|
276
|
-
for (const category of pluralCategories) {
|
|
277
|
-
const finalKey = isOrdinal
|
|
278
|
-
? `${key}_${context}${pluralSeparator}ordinal${pluralSeparator}${category}`
|
|
279
|
-
: `${key}_${context}${pluralSeparator}${category}`
|
|
280
|
-
|
|
281
|
-
pluginContext.addKey({
|
|
282
|
-
key: finalKey,
|
|
283
|
-
ns,
|
|
284
|
-
defaultValue,
|
|
285
|
-
hasCount: true,
|
|
286
|
-
isOrdinal
|
|
287
|
-
})
|
|
288
|
-
}
|
|
289
|
-
} catch (e) {
|
|
290
|
-
// Fallback if Intl API fails
|
|
291
|
-
pluginContext.addKey({ key: `${key}_${context}`, ns, defaultValue })
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* Parses default value from the remainder of a comment after a translation function call.
|
|
297
|
-
* Supports both string literals and object syntax with defaultValue property.
|
|
298
|
-
*
|
|
299
|
-
* @param remainder - The remaining text after the translation key
|
|
300
|
-
* @returns The parsed default value or undefined if none found
|
|
301
|
-
*
|
|
302
|
-
* @internal
|
|
303
|
-
*/
|
|
304
|
-
function parseDefaultValueFromComment (remainder: string): string | undefined {
|
|
305
|
-
// Simple string default: , 'VALUE' or , "VALUE"
|
|
306
|
-
const dvString = /^\s*,\s*(['"])(.*?)\1/.exec(remainder)
|
|
307
|
-
if (dvString) return dvString[2]
|
|
308
|
-
|
|
309
|
-
// Object with defaultValue: , { defaultValue: 'VALUE', ... }
|
|
310
|
-
const dvObj = /^\s*,\s*\{[^}]*defaultValue\s*:\s*(['"])(.*?)\1/.exec(remainder)
|
|
311
|
-
if (dvObj) return dvObj[2]
|
|
312
|
-
|
|
313
|
-
return undefined
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
/**
|
|
317
|
-
* Parses namespace from the remainder of a comment after a translation function call.
|
|
318
|
-
* Looks for namespace specified in options object syntax.
|
|
319
|
-
*
|
|
320
|
-
* @param remainder - The remaining text after the translation key
|
|
321
|
-
* @returns The parsed namespace or undefined if none found
|
|
322
|
-
*
|
|
323
|
-
* @internal
|
|
324
|
-
*/
|
|
325
|
-
function parseNsFromComment (remainder: string): string | undefined {
|
|
326
|
-
// Look for ns in an options object, e.g., { ns: 'common' }
|
|
327
|
-
const nsObj = /^\s*,\s*\{[^}]*ns\s*:\s*(['"])(.*?)\1/.exec(remainder)
|
|
328
|
-
if (nsObj) return nsObj[2]
|
|
329
|
-
|
|
330
|
-
return undefined
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* Collects all comment texts from source code, both single-line and multi-line.
|
|
335
|
-
* Deduplicates comments to avoid processing the same text multiple times.
|
|
336
|
-
*
|
|
337
|
-
* @param src - The source code to extract comments from
|
|
338
|
-
* @returns Array of unique comment text content
|
|
339
|
-
*
|
|
340
|
-
* @internal
|
|
341
|
-
*/
|
|
342
|
-
function collectCommentTexts (src: string): string[] {
|
|
343
|
-
const texts: string[] = []
|
|
344
|
-
const seen = new Set<string>()
|
|
345
|
-
|
|
346
|
-
const commentRegex = /\/\/(.*)|\/\*([\s\S]*?)\*\//g
|
|
347
|
-
let cmatch: RegExpExecArray | null
|
|
348
|
-
while ((cmatch = commentRegex.exec(src)) !== null) {
|
|
349
|
-
const content = cmatch[1] ?? cmatch[2]
|
|
350
|
-
const s = content.trim()
|
|
351
|
-
if (s && !seen.has(s)) {
|
|
352
|
-
seen.add(s)
|
|
353
|
-
texts.push(s)
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
return texts
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
/**
|
|
361
|
-
* Parses context from the remainder of a comment after a translation function call.
|
|
362
|
-
* Looks for context specified in options object syntax.
|
|
363
|
-
*
|
|
364
|
-
* @param remainder - The remaining text after the translation key
|
|
365
|
-
* @returns The parsed context value or undefined if none found
|
|
366
|
-
*
|
|
367
|
-
* @internal
|
|
368
|
-
*/
|
|
369
|
-
function parseContextFromComment (remainder: string): string | undefined {
|
|
370
|
-
// Look for context in an options object, e.g., { context: 'male' }
|
|
371
|
-
const contextObj = /^\s*,\s*\{[^}]*context\s*:\s*(['"])(.*?)\1/.exec(remainder)
|
|
372
|
-
if (contextObj) return contextObj[2]
|
|
373
|
-
|
|
374
|
-
return undefined
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
/**
|
|
378
|
-
* Parses count from the remainder of a comment after a translation function call.
|
|
379
|
-
* Looks for count specified in options object syntax.
|
|
380
|
-
*
|
|
381
|
-
* @param remainder - The remaining text after the translation key
|
|
382
|
-
* @returns The parsed count value or undefined if none found
|
|
383
|
-
*
|
|
384
|
-
* @internal
|
|
385
|
-
*/
|
|
386
|
-
function parseCountFromComment (remainder: string): number | undefined {
|
|
387
|
-
// Look for count in an options object, e.g., { count: 1 }
|
|
388
|
-
const countObj = /^\s*,\s*\{[^}]*count\s*:\s*(\d+)/.exec(remainder)
|
|
389
|
-
if (countObj) return parseInt(countObj[1], 10)
|
|
390
|
-
|
|
391
|
-
return undefined
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
/**
|
|
395
|
-
* Parses ordinal flag from the remainder of a comment after a translation function call.
|
|
396
|
-
* Looks for ordinal specified in options object syntax.
|
|
397
|
-
*
|
|
398
|
-
* @param remainder - The remaining text after the translation key
|
|
399
|
-
* @returns The parsed ordinal value or undefined if none found
|
|
400
|
-
*
|
|
401
|
-
* @internal
|
|
402
|
-
*/
|
|
403
|
-
function parseOrdinalFromComment (remainder: string): boolean | undefined {
|
|
404
|
-
// Look for ordinal in an options object, e.g., { ordinal: true }
|
|
405
|
-
const ordinalObj = /^\s*,\s*\{[^}]*ordinal\s*:\s*(true|false)/.exec(remainder)
|
|
406
|
-
if (ordinalObj) return ordinalObj[1] === 'true'
|
|
407
|
-
|
|
408
|
-
return undefined
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
/**
|
|
412
|
-
* Converts a glob pattern to a regular expression.
|
|
413
|
-
* Supports basic glob patterns with * wildcards.
|
|
414
|
-
*
|
|
415
|
-
* @param glob - The glob pattern to convert
|
|
416
|
-
* @returns A RegExp that matches the glob pattern
|
|
417
|
-
*
|
|
418
|
-
* @internal
|
|
419
|
-
*/
|
|
420
|
-
function globToRegex (glob: string): RegExp {
|
|
421
|
-
const escaped = glob.replace(/[.+?^${}()|[\]\\]/g, '\\$&')
|
|
422
|
-
const regexString = `^${escaped.replace(/\*/g, '.*')}$`
|
|
423
|
-
return new RegExp(regexString)
|
|
424
|
-
}
|