@hyperfixi/vite-plugin 2.0.0 → 2.2.0
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/index.cjs +360 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +173 -1
- package/dist/index.d.ts +173 -1
- package/dist/index.js +357 -1
- package/dist/index.js.map +1 -1
- package/package.json +11 -3
package/dist/index.js
CHANGED
|
@@ -473,6 +473,8 @@ var POLISH_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
473
473
|
"zwi\u0119ksz",
|
|
474
474
|
"zwieksz",
|
|
475
475
|
"zmniejsz",
|
|
476
|
+
"uzyskaj",
|
|
477
|
+
"pobierz",
|
|
476
478
|
"wywo\u0142aj",
|
|
477
479
|
"wywolaj",
|
|
478
480
|
"wyzw\xF3l",
|
|
@@ -1823,6 +1825,15 @@ async function evaluate(node, ctx) {
|
|
|
1823
1825
|
const obj = await evaluate(node.object, ctx);
|
|
1824
1826
|
if (obj == null) return undefined;
|
|
1825
1827
|
const prop = node.computed ? await evaluate(node.property, ctx) : node.property;
|
|
1828
|
+
if (prop === 'values' && obj instanceof Element) {
|
|
1829
|
+
if (obj instanceof HTMLFormElement) return new FormData(obj);
|
|
1830
|
+
const fd = new FormData();
|
|
1831
|
+
obj.querySelectorAll('input, select, textarea').forEach(input => {
|
|
1832
|
+
const name = input.getAttribute('name');
|
|
1833
|
+
if (name && 'value' in input) fd.append(name, input.value);
|
|
1834
|
+
});
|
|
1835
|
+
return fd;
|
|
1836
|
+
}
|
|
1826
1837
|
return obj[prop];
|
|
1827
1838
|
|
|
1828
1839
|
case 'call': {
|
|
@@ -2907,6 +2918,9 @@ function compileExpression(node) {
|
|
|
2907
2918
|
if (prop.startsWith("*")) {
|
|
2908
2919
|
return `${obj}.style.${prop.slice(1)}`;
|
|
2909
2920
|
}
|
|
2921
|
+
if (prop === "values") {
|
|
2922
|
+
return `(function(el){if(el instanceof HTMLFormElement)return new FormData(el);var fd=new FormData();el.querySelectorAll('input,select,textarea').forEach(function(i){var n=i.getAttribute('name');if(n&&'value'in i)fd.append(n,i.value)});return fd})(${obj})`;
|
|
2923
|
+
}
|
|
2910
2924
|
return `${obj}.${prop}`;
|
|
2911
2925
|
}
|
|
2912
2926
|
case "member": {
|
|
@@ -3230,6 +3244,290 @@ function extractScripts(html) {
|
|
|
3230
3244
|
return scripts;
|
|
3231
3245
|
}
|
|
3232
3246
|
|
|
3247
|
+
// src/server-bridge-integration.ts
|
|
3248
|
+
import { resolve, join } from "path";
|
|
3249
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
3250
|
+
var serverBridge = null;
|
|
3251
|
+
var loadAttempted = false;
|
|
3252
|
+
var lastRouteHash = "";
|
|
3253
|
+
async function loadServerBridge(debug) {
|
|
3254
|
+
if (loadAttempted) return serverBridge;
|
|
3255
|
+
loadAttempted = true;
|
|
3256
|
+
try {
|
|
3257
|
+
const mod = await import("@hyperfixi/server-bridge");
|
|
3258
|
+
serverBridge = mod;
|
|
3259
|
+
if (debug) {
|
|
3260
|
+
console.log("[hyperfixi] Server-bridge loaded successfully");
|
|
3261
|
+
}
|
|
3262
|
+
return serverBridge;
|
|
3263
|
+
} catch {
|
|
3264
|
+
console.warn(
|
|
3265
|
+
"[hyperfixi] @hyperfixi/server-bridge is not installed. Install it to enable server route generation: npm install @hyperfixi/server-bridge"
|
|
3266
|
+
);
|
|
3267
|
+
return null;
|
|
3268
|
+
}
|
|
3269
|
+
}
|
|
3270
|
+
function computeRouteHash(routes) {
|
|
3271
|
+
return routes.map((r) => `${r.method}:${r.path}`).sort().join("|");
|
|
3272
|
+
}
|
|
3273
|
+
async function runServerBridge(cwd, options, debug, force) {
|
|
3274
|
+
const mod = serverBridge ?? await loadServerBridge(debug);
|
|
3275
|
+
if (!mod) return;
|
|
3276
|
+
try {
|
|
3277
|
+
const outputDir = resolve(cwd, options.output ?? "./server/routes");
|
|
3278
|
+
const result = await mod.generate({
|
|
3279
|
+
dir: cwd,
|
|
3280
|
+
framework: options.framework ?? "express",
|
|
3281
|
+
output: options.output,
|
|
3282
|
+
typescript: options.typescript,
|
|
3283
|
+
ignore: options.ignore
|
|
3284
|
+
});
|
|
3285
|
+
const routeHash = computeRouteHash(result.routes);
|
|
3286
|
+
if (!force && routeHash === lastRouteHash) {
|
|
3287
|
+
if (debug) {
|
|
3288
|
+
console.log("[hyperfixi] Server-bridge: routes unchanged, skipping generation");
|
|
3289
|
+
}
|
|
3290
|
+
return;
|
|
3291
|
+
}
|
|
3292
|
+
lastRouteHash = routeHash;
|
|
3293
|
+
if (result.routes.length === 0) {
|
|
3294
|
+
if (debug) {
|
|
3295
|
+
console.log("[hyperfixi] Server-bridge: no routes found");
|
|
3296
|
+
}
|
|
3297
|
+
return;
|
|
3298
|
+
}
|
|
3299
|
+
await mkdir(outputDir, { recursive: true });
|
|
3300
|
+
for (const file of result.generated.files) {
|
|
3301
|
+
const filePath = join(outputDir, file.path);
|
|
3302
|
+
const fileDir = join(filePath, "..");
|
|
3303
|
+
await mkdir(fileDir, { recursive: true });
|
|
3304
|
+
await writeFile(filePath, file.content, "utf-8");
|
|
3305
|
+
}
|
|
3306
|
+
const manifest = mod.createManifest(result.routes);
|
|
3307
|
+
await mod.saveManifest(outputDir, manifest);
|
|
3308
|
+
if (debug) {
|
|
3309
|
+
console.log(
|
|
3310
|
+
`[hyperfixi] Server-bridge: generated ${result.generated.files.length} file(s) for ${result.routes.length} route(s) in ${outputDir}/`
|
|
3311
|
+
);
|
|
3312
|
+
}
|
|
3313
|
+
if (result.scan.conflicts.length > 0) {
|
|
3314
|
+
console.warn(
|
|
3315
|
+
`[hyperfixi] Server-bridge: ${result.scan.conflicts.length} route conflict(s) detected`
|
|
3316
|
+
);
|
|
3317
|
+
}
|
|
3318
|
+
} catch (err) {
|
|
3319
|
+
console.error(
|
|
3320
|
+
"[hyperfixi] Server-bridge generation failed:",
|
|
3321
|
+
err instanceof Error ? err.message : err
|
|
3322
|
+
);
|
|
3323
|
+
}
|
|
3324
|
+
}
|
|
3325
|
+
|
|
3326
|
+
// src/domain-scanner.ts
|
|
3327
|
+
function buildAttributePatterns(attributes) {
|
|
3328
|
+
const patterns = [];
|
|
3329
|
+
for (const attr of attributes) {
|
|
3330
|
+
const escaped = attr.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3331
|
+
patterns.push(new RegExp(`${escaped}\\s*=\\s*"([^"]+)"`, "g"));
|
|
3332
|
+
patterns.push(new RegExp(`${escaped}\\s*=\\s*'([^']+)'`, "g"));
|
|
3333
|
+
patterns.push(new RegExp(`${escaped}\\s*=\\s*\`([^\`]+)\``, "g"));
|
|
3334
|
+
}
|
|
3335
|
+
return patterns;
|
|
3336
|
+
}
|
|
3337
|
+
function buildScriptPatterns(scriptTypes) {
|
|
3338
|
+
return scriptTypes.map((type) => {
|
|
3339
|
+
const escaped = type.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3340
|
+
return new RegExp(`<script[^>]*type=["']?${escaped}["']?[^>]*>([\\s\\S]*?)<\\/script>`, "gi");
|
|
3341
|
+
});
|
|
3342
|
+
}
|
|
3343
|
+
function detectKeywords(snippet, keywords) {
|
|
3344
|
+
const detectedKeywords = /* @__PURE__ */ new Set();
|
|
3345
|
+
const detectedLanguages = /* @__PURE__ */ new Set();
|
|
3346
|
+
for (const [lang, kwList] of Object.entries(keywords)) {
|
|
3347
|
+
for (const kw of kwList) {
|
|
3348
|
+
const isLatin = /^[a-zA-Z]/.test(kw);
|
|
3349
|
+
const found = isLatin ? new RegExp(`\\b${kw.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`, "i").test(snippet) : snippet.includes(kw);
|
|
3350
|
+
if (found) {
|
|
3351
|
+
detectedKeywords.add(kw);
|
|
3352
|
+
detectedLanguages.add(lang);
|
|
3353
|
+
}
|
|
3354
|
+
}
|
|
3355
|
+
}
|
|
3356
|
+
return { detectedKeywords, detectedLanguages };
|
|
3357
|
+
}
|
|
3358
|
+
var DomainScanner = class {
|
|
3359
|
+
constructor(rules) {
|
|
3360
|
+
this.rules = rules;
|
|
3361
|
+
const allAttrs = rules.flatMap((r) => [...r.attributes]);
|
|
3362
|
+
const allScriptTypes = rules.flatMap((r) => r.scriptTypes ? [...r.scriptTypes] : []);
|
|
3363
|
+
const parts = [];
|
|
3364
|
+
for (const attr of allAttrs) {
|
|
3365
|
+
parts.push(attr.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
|
|
3366
|
+
}
|
|
3367
|
+
for (const type of allScriptTypes) {
|
|
3368
|
+
parts.push(type.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
|
|
3369
|
+
}
|
|
3370
|
+
this.quickCheckPattern = parts.length > 0 ? new RegExp(parts.join("|"), "i") : null;
|
|
3371
|
+
}
|
|
3372
|
+
/**
|
|
3373
|
+
* Fast pre-check: does this code contain any domain-related attributes?
|
|
3374
|
+
*/
|
|
3375
|
+
hasAnyDomainUsage(code) {
|
|
3376
|
+
if (!this.quickCheckPattern) return false;
|
|
3377
|
+
return this.quickCheckPattern.test(code);
|
|
3378
|
+
}
|
|
3379
|
+
/**
|
|
3380
|
+
* Scan a file for all registered domain syntaxes.
|
|
3381
|
+
* Returns one DomainFileUsage per domain that had matches.
|
|
3382
|
+
*/
|
|
3383
|
+
scan(code, _id) {
|
|
3384
|
+
const results = [];
|
|
3385
|
+
for (const rule of this.rules) {
|
|
3386
|
+
const snippets = [];
|
|
3387
|
+
const attrPatterns = buildAttributePatterns(rule.attributes);
|
|
3388
|
+
for (const pattern of attrPatterns) {
|
|
3389
|
+
pattern.lastIndex = 0;
|
|
3390
|
+
let match;
|
|
3391
|
+
while (match = pattern.exec(code)) {
|
|
3392
|
+
const value = match[1].trim();
|
|
3393
|
+
if (value) snippets.push(value);
|
|
3394
|
+
}
|
|
3395
|
+
}
|
|
3396
|
+
if (rule.scriptTypes) {
|
|
3397
|
+
const scriptPatterns = buildScriptPatterns(rule.scriptTypes);
|
|
3398
|
+
for (const pattern of scriptPatterns) {
|
|
3399
|
+
pattern.lastIndex = 0;
|
|
3400
|
+
let match;
|
|
3401
|
+
while (match = pattern.exec(code)) {
|
|
3402
|
+
const value = match[1].trim();
|
|
3403
|
+
if (value) snippets.push(value);
|
|
3404
|
+
}
|
|
3405
|
+
}
|
|
3406
|
+
}
|
|
3407
|
+
if (snippets.length === 0) continue;
|
|
3408
|
+
const allDetectedKeywords = /* @__PURE__ */ new Set();
|
|
3409
|
+
const allDetectedLanguages = /* @__PURE__ */ new Set();
|
|
3410
|
+
if (rule.keywords) {
|
|
3411
|
+
for (const snippet of snippets) {
|
|
3412
|
+
const { detectedKeywords, detectedLanguages } = detectKeywords(snippet, rule.keywords);
|
|
3413
|
+
for (const kw of detectedKeywords) allDetectedKeywords.add(kw);
|
|
3414
|
+
for (const lang of detectedLanguages) allDetectedLanguages.add(lang);
|
|
3415
|
+
}
|
|
3416
|
+
}
|
|
3417
|
+
results.push({
|
|
3418
|
+
domain: rule.domain,
|
|
3419
|
+
detectedKeywords: allDetectedKeywords,
|
|
3420
|
+
detectedLanguages: allDetectedLanguages,
|
|
3421
|
+
snippetCount: snippets.length
|
|
3422
|
+
});
|
|
3423
|
+
}
|
|
3424
|
+
return results;
|
|
3425
|
+
}
|
|
3426
|
+
};
|
|
3427
|
+
function descriptorToScanRule(descriptor) {
|
|
3428
|
+
if (!descriptor.scanConfig) return null;
|
|
3429
|
+
return {
|
|
3430
|
+
domain: descriptor.name,
|
|
3431
|
+
attributes: [...descriptor.scanConfig.attributes],
|
|
3432
|
+
scriptTypes: descriptor.scanConfig.scriptTypes ? [...descriptor.scanConfig.scriptTypes] : void 0,
|
|
3433
|
+
keywords: descriptor.scanConfig.keywords ? Object.fromEntries(
|
|
3434
|
+
Object.entries(descriptor.scanConfig.keywords).map(([k, v]) => [k, [...v]])
|
|
3435
|
+
) : void 0
|
|
3436
|
+
};
|
|
3437
|
+
}
|
|
3438
|
+
|
|
3439
|
+
// src/domain-aggregator.ts
|
|
3440
|
+
var DomainAggregator = class {
|
|
3441
|
+
constructor() {
|
|
3442
|
+
this.fileUsage = /* @__PURE__ */ new Map();
|
|
3443
|
+
this.cache = null;
|
|
3444
|
+
}
|
|
3445
|
+
/**
|
|
3446
|
+
* Add or update domain usage for a file.
|
|
3447
|
+
* Returns true if usage changed (invalidates cache).
|
|
3448
|
+
*/
|
|
3449
|
+
add(filePath, usage) {
|
|
3450
|
+
const existing = this.fileUsage.get(filePath);
|
|
3451
|
+
const changed = !existing || !this.isEqual(existing, usage);
|
|
3452
|
+
if (changed) {
|
|
3453
|
+
this.fileUsage.set(filePath, usage);
|
|
3454
|
+
this.cache = null;
|
|
3455
|
+
}
|
|
3456
|
+
return changed;
|
|
3457
|
+
}
|
|
3458
|
+
/**
|
|
3459
|
+
* Remove a file's domain usage.
|
|
3460
|
+
* Returns true if the file was tracked.
|
|
3461
|
+
*/
|
|
3462
|
+
remove(filePath) {
|
|
3463
|
+
const had = this.fileUsage.has(filePath);
|
|
3464
|
+
if (had) {
|
|
3465
|
+
this.fileUsage.delete(filePath);
|
|
3466
|
+
this.cache = null;
|
|
3467
|
+
}
|
|
3468
|
+
return had;
|
|
3469
|
+
}
|
|
3470
|
+
/**
|
|
3471
|
+
* Get aggregated usage across all files.
|
|
3472
|
+
* Result is cached until add/remove changes it.
|
|
3473
|
+
*/
|
|
3474
|
+
getUsage() {
|
|
3475
|
+
if (this.cache) return this.cache;
|
|
3476
|
+
const domainMap = /* @__PURE__ */ new Map();
|
|
3477
|
+
for (const usages of this.fileUsage.values()) {
|
|
3478
|
+
for (const usage of usages) {
|
|
3479
|
+
let entry = domainMap.get(usage.domain);
|
|
3480
|
+
if (!entry) {
|
|
3481
|
+
entry = {
|
|
3482
|
+
detectedKeywords: /* @__PURE__ */ new Set(),
|
|
3483
|
+
detectedLanguages: /* @__PURE__ */ new Set(),
|
|
3484
|
+
fileCount: 0,
|
|
3485
|
+
totalSnippets: 0
|
|
3486
|
+
};
|
|
3487
|
+
domainMap.set(usage.domain, entry);
|
|
3488
|
+
}
|
|
3489
|
+
entry.fileCount++;
|
|
3490
|
+
entry.totalSnippets += usage.snippetCount;
|
|
3491
|
+
for (const kw of usage.detectedKeywords) entry.detectedKeywords.add(kw);
|
|
3492
|
+
for (const lang of usage.detectedLanguages) entry.detectedLanguages.add(lang);
|
|
3493
|
+
}
|
|
3494
|
+
}
|
|
3495
|
+
this.cache = Array.from(domainMap.entries()).map(([domain, data]) => ({
|
|
3496
|
+
domain,
|
|
3497
|
+
detectedKeywords: data.detectedKeywords,
|
|
3498
|
+
detectedLanguages: data.detectedLanguages,
|
|
3499
|
+
fileCount: data.fileCount,
|
|
3500
|
+
totalSnippets: data.totalSnippets
|
|
3501
|
+
}));
|
|
3502
|
+
return this.cache;
|
|
3503
|
+
}
|
|
3504
|
+
/**
|
|
3505
|
+
* Get aggregated usage for a specific domain.
|
|
3506
|
+
*/
|
|
3507
|
+
getUsageForDomain(domain) {
|
|
3508
|
+
return this.getUsage().find((u) => u.domain === domain) ?? null;
|
|
3509
|
+
}
|
|
3510
|
+
/**
|
|
3511
|
+
* Clear all tracked data.
|
|
3512
|
+
*/
|
|
3513
|
+
clear() {
|
|
3514
|
+
this.fileUsage.clear();
|
|
3515
|
+
this.cache = null;
|
|
3516
|
+
}
|
|
3517
|
+
// ---------------------------------------------------------------------------
|
|
3518
|
+
// Private
|
|
3519
|
+
// ---------------------------------------------------------------------------
|
|
3520
|
+
isEqual(a, b) {
|
|
3521
|
+
if (a.length !== b.length) return false;
|
|
3522
|
+
for (let i = 0; i < a.length; i++) {
|
|
3523
|
+
if (a[i].domain !== b[i].domain) return false;
|
|
3524
|
+
if (a[i].snippetCount !== b[i].snippetCount) return false;
|
|
3525
|
+
if (a[i].detectedKeywords.size !== b[i].detectedKeywords.size) return false;
|
|
3526
|
+
}
|
|
3527
|
+
return true;
|
|
3528
|
+
}
|
|
3529
|
+
};
|
|
3530
|
+
|
|
3233
3531
|
// src/index.ts
|
|
3234
3532
|
var VIRTUAL_MODULE_ID = "virtual:hyperfixi";
|
|
3235
3533
|
var RESOLVED_VIRTUAL_MODULE_ID = "\0" + VIRTUAL_MODULE_ID;
|
|
@@ -3239,6 +3537,8 @@ function hyperfixi(options = {}) {
|
|
|
3239
3537
|
const scanner = new Scanner(options);
|
|
3240
3538
|
const aggregator = new Aggregator();
|
|
3241
3539
|
const generator = new Generator(options);
|
|
3540
|
+
const domainScanner = options.domains && options.domains.length > 0 ? new DomainScanner(options.domains) : null;
|
|
3541
|
+
const domainAggregator = domainScanner ? new DomainAggregator() : null;
|
|
3242
3542
|
let server = null;
|
|
3243
3543
|
let cachedBundle = null;
|
|
3244
3544
|
let lastUsageHash = "";
|
|
@@ -3341,11 +3641,14 @@ function hyperfixi(options = {}) {
|
|
|
3341
3641
|
/**
|
|
3342
3642
|
* Configure plugin based on Vite mode
|
|
3343
3643
|
*/
|
|
3344
|
-
configResolved(config) {
|
|
3644
|
+
async configResolved(config) {
|
|
3345
3645
|
isDev = config.command === "serve";
|
|
3346
3646
|
if (options.debug) {
|
|
3347
3647
|
console.log("[hyperfixi] Plugin initialized, mode:", isDev ? "development" : "production");
|
|
3348
3648
|
}
|
|
3649
|
+
if (options.serverBridge) {
|
|
3650
|
+
await loadServerBridge(options.debug);
|
|
3651
|
+
}
|
|
3349
3652
|
},
|
|
3350
3653
|
/**
|
|
3351
3654
|
* Store server reference and pre-scan HTML files for HMR
|
|
@@ -3358,6 +3661,25 @@ function hyperfixi(options = {}) {
|
|
|
3358
3661
|
}
|
|
3359
3662
|
const scannedFiles = await scanner.scanProject(cwd);
|
|
3360
3663
|
aggregator.loadFromScan(scannedFiles);
|
|
3664
|
+
if (domainScanner && domainAggregator) {
|
|
3665
|
+
for (const [filePath] of scannedFiles) {
|
|
3666
|
+
try {
|
|
3667
|
+
const fs = await import("fs");
|
|
3668
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
3669
|
+
if (domainScanner.hasAnyDomainUsage(content)) {
|
|
3670
|
+
const domainUsages = domainScanner.scan(content, filePath);
|
|
3671
|
+
if (domainUsages.length > 0) {
|
|
3672
|
+
domainAggregator.add(filePath, domainUsages);
|
|
3673
|
+
}
|
|
3674
|
+
}
|
|
3675
|
+
} catch {
|
|
3676
|
+
}
|
|
3677
|
+
}
|
|
3678
|
+
if (options.debug) {
|
|
3679
|
+
const domainSummary = domainAggregator.getUsage();
|
|
3680
|
+
console.log("[hyperfixi] Domain pre-scan:", domainSummary);
|
|
3681
|
+
}
|
|
3682
|
+
}
|
|
3361
3683
|
if (options.debug) {
|
|
3362
3684
|
const summary = aggregator.getSummary();
|
|
3363
3685
|
console.log("[hyperfixi] Pre-scan complete:", summary);
|
|
@@ -3404,6 +3726,12 @@ function hyperfixi(options = {}) {
|
|
|
3404
3726
|
}
|
|
3405
3727
|
const usage = scanner.scan(code, id);
|
|
3406
3728
|
const changed = aggregator.add(id, usage);
|
|
3729
|
+
if (domainScanner && domainAggregator && domainScanner.hasAnyDomainUsage(code)) {
|
|
3730
|
+
const domainUsages = domainScanner.scan(code, id);
|
|
3731
|
+
if (domainUsages.length > 0) {
|
|
3732
|
+
domainAggregator.add(id, domainUsages);
|
|
3733
|
+
}
|
|
3734
|
+
}
|
|
3407
3735
|
if (changed && server) {
|
|
3408
3736
|
setImmediate(() => {
|
|
3409
3737
|
const currentHash = computeUsageHash(aggregator.getUsage());
|
|
@@ -3433,6 +3761,9 @@ function hyperfixi(options = {}) {
|
|
|
3433
3761
|
invalidateVirtualModule();
|
|
3434
3762
|
}
|
|
3435
3763
|
}
|
|
3764
|
+
if (options.serverBridge && server) {
|
|
3765
|
+
await runServerBridge(server.config.root, options.serverBridge, options.debug);
|
|
3766
|
+
}
|
|
3436
3767
|
} catch {
|
|
3437
3768
|
if (aggregator.remove(file)) {
|
|
3438
3769
|
invalidateVirtualModule();
|
|
@@ -3463,6 +3794,25 @@ function hyperfixi(options = {}) {
|
|
|
3463
3794
|
}
|
|
3464
3795
|
const scannedFiles = await scanner.scanProject(cwd);
|
|
3465
3796
|
aggregator.loadFromScan(scannedFiles);
|
|
3797
|
+
if (domainScanner && domainAggregator) {
|
|
3798
|
+
for (const [filePath] of scannedFiles) {
|
|
3799
|
+
try {
|
|
3800
|
+
const fs = await import("fs");
|
|
3801
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
3802
|
+
if (domainScanner.hasAnyDomainUsage(content)) {
|
|
3803
|
+
const domainUsages = domainScanner.scan(content, filePath);
|
|
3804
|
+
if (domainUsages.length > 0) {
|
|
3805
|
+
domainAggregator.add(filePath, domainUsages);
|
|
3806
|
+
}
|
|
3807
|
+
}
|
|
3808
|
+
} catch {
|
|
3809
|
+
}
|
|
3810
|
+
}
|
|
3811
|
+
if (options.debug) {
|
|
3812
|
+
const domainSummary = domainAggregator.getUsage();
|
|
3813
|
+
console.log("[hyperfixi] Domain build scan:", domainSummary);
|
|
3814
|
+
}
|
|
3815
|
+
}
|
|
3466
3816
|
if (mode === "compile") {
|
|
3467
3817
|
const usage = aggregator.getUsage();
|
|
3468
3818
|
if (usage.detectedLanguages.size > 0) {
|
|
@@ -3488,17 +3838,23 @@ function hyperfixi(options = {}) {
|
|
|
3488
3838
|
languages: summary.languages
|
|
3489
3839
|
});
|
|
3490
3840
|
}
|
|
3841
|
+
if (options.serverBridge) {
|
|
3842
|
+
await runServerBridge(cwd, options.serverBridge, options.debug, true);
|
|
3843
|
+
}
|
|
3491
3844
|
}
|
|
3492
3845
|
}
|
|
3493
3846
|
};
|
|
3494
3847
|
}
|
|
3495
3848
|
var index_default = hyperfixi;
|
|
3496
3849
|
export {
|
|
3850
|
+
DomainAggregator,
|
|
3851
|
+
DomainScanner,
|
|
3497
3852
|
REGIONS,
|
|
3498
3853
|
SUPPORTED_LANGUAGES,
|
|
3499
3854
|
clearCustomKeywords,
|
|
3500
3855
|
clearSemanticParser,
|
|
3501
3856
|
index_default as default,
|
|
3857
|
+
descriptorToScanRule,
|
|
3502
3858
|
detectLanguages,
|
|
3503
3859
|
getAllLanguageCodes,
|
|
3504
3860
|
getKeywordsForLanguage,
|