@ripast/vue 0.0.1 → 0.2.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/dist/index.mjs +351 -2
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
2
|
-
import { join, resolve } from "node:path";
|
|
3
|
-
import { extractTemplateExpressions, posToLineCol, rewriteTemplateReferences } from "@ripast/core/adapter";
|
|
2
|
+
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
3
|
+
import { extractTemplateExpressions, hyphenateVueName, isInsideAutoImportScope, posToLineCol, rewriteTemplateReferences, rgFiles, scan } from "@ripast/core/adapter";
|
|
4
4
|
import { URI } from "vscode-uri";
|
|
5
5
|
import process from "node:process";
|
|
6
6
|
import { FileType, createLanguage, createLanguageService, createUriMap } from "@volar/language-service";
|
|
@@ -273,6 +273,346 @@ async function getDiags(vue, fileName) {
|
|
|
273
273
|
function diagKey(d) {
|
|
274
274
|
return `${d.range.start.line}:${d.range.start.character}:${d.code ?? ""}:${d.message}`;
|
|
275
275
|
}
|
|
276
|
+
const MODULE_EXT_RE = /\.(?:tsx?|jsx?|mts|cts|mjs|cjs|vue)$/;
|
|
277
|
+
const WIN_SEP_RE = /\\/g;
|
|
278
|
+
function isGeneratedNuxtPath(cwd, filePath) {
|
|
279
|
+
const rel = relative(cwd, filePath).replace(/\\/g, "/");
|
|
280
|
+
return rel === ".nuxt" || rel.startsWith(".nuxt/");
|
|
281
|
+
}
|
|
282
|
+
function removeGeneratedNuxtChanges(cwd, changes) {
|
|
283
|
+
for (let i = changes.length - 1; i >= 0; i--) if (isGeneratedNuxtPath(cwd, changes[i].path)) changes.splice(i, 1);
|
|
284
|
+
}
|
|
285
|
+
function loadNuxtPathAliases(cwd) {
|
|
286
|
+
const out = [];
|
|
287
|
+
const seen = /* @__PURE__ */ new Set();
|
|
288
|
+
const candidates = [
|
|
289
|
+
join(cwd, ".nuxt/tsconfig.json"),
|
|
290
|
+
join(cwd, ".nuxt/tsconfig.app.json"),
|
|
291
|
+
join(cwd, "tsconfig.json")
|
|
292
|
+
];
|
|
293
|
+
for (const candidate of candidates) {
|
|
294
|
+
if (!existsSync(candidate)) continue;
|
|
295
|
+
for (const alias of readTsconfigPaths(candidate)) {
|
|
296
|
+
const key = `${alias.pattern}|${alias.targets.join(",")}`;
|
|
297
|
+
if (seen.has(key)) continue;
|
|
298
|
+
seen.add(key);
|
|
299
|
+
out.push(alias);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return out;
|
|
303
|
+
}
|
|
304
|
+
function readTsconfigPaths(tsconfigPath) {
|
|
305
|
+
const visited = /* @__PURE__ */ new Set();
|
|
306
|
+
return collect(tsconfigPath);
|
|
307
|
+
function collect(path) {
|
|
308
|
+
if (visited.has(path) || !existsSync(path)) return [];
|
|
309
|
+
visited.add(path);
|
|
310
|
+
let json;
|
|
311
|
+
try {
|
|
312
|
+
json = JSON.parse(stripJsonComments(readFileSync(path, "utf8")));
|
|
313
|
+
} catch {
|
|
314
|
+
return [];
|
|
315
|
+
}
|
|
316
|
+
const out = [];
|
|
317
|
+
const co = json.compilerOptions ?? {};
|
|
318
|
+
const baseUrl = co.baseUrl ? resolve(dirname(path), co.baseUrl) : dirname(path);
|
|
319
|
+
const paths = co.paths ?? {};
|
|
320
|
+
for (const [pattern, raw] of Object.entries(paths)) {
|
|
321
|
+
if (!Array.isArray(raw) || !raw.length) continue;
|
|
322
|
+
const wildcard = pattern.endsWith("/*");
|
|
323
|
+
const targets = raw.map((t) => resolve(baseUrl, wildcard ? t.replace(/\/\*$/, "") : t));
|
|
324
|
+
out.push({
|
|
325
|
+
pattern,
|
|
326
|
+
targets,
|
|
327
|
+
wildcard
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
if (json.extends) {
|
|
331
|
+
const exts = Array.isArray(json.extends) ? json.extends : [json.extends];
|
|
332
|
+
for (const ext of exts) {
|
|
333
|
+
const resolved = ext.startsWith(".") ? resolve(dirname(path), ext) : ext;
|
|
334
|
+
const withExt = /\.json$/.test(resolved) ? resolved : `${resolved}.json`;
|
|
335
|
+
out.push(...collect(withExt));
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return out;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
function stripJsonComments(source) {
|
|
342
|
+
return source.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/.*$/gm, "$1");
|
|
343
|
+
}
|
|
344
|
+
function resolveBestImportSpecifier(fromFile, toFile, aliases, oldSpec) {
|
|
345
|
+
const targetAlias = pickAliasFor(toFile, aliases);
|
|
346
|
+
const sourceAlias = pickAliasFor(fromFile, aliases);
|
|
347
|
+
if (!!targetAlias && (!sourceAlias || sourceAlias.matchedRoot !== targetAlias.matchedRoot) && targetAlias) return formatAliasSpecifier(targetAlias, oldSpec);
|
|
348
|
+
return formatRelativeSpecifier(fromFile, toFile, oldSpec);
|
|
349
|
+
}
|
|
350
|
+
function pickAliasFor(file, aliases) {
|
|
351
|
+
const normFile = file.replace(WIN_SEP_RE, "/");
|
|
352
|
+
let best = null;
|
|
353
|
+
for (const alias of aliases) for (const target of alias.targets) {
|
|
354
|
+
const normTarget = target.replace(WIN_SEP_RE, "/");
|
|
355
|
+
if (alias.wildcard) {
|
|
356
|
+
if (normFile === normTarget || normFile.startsWith(`${normTarget}/`)) {
|
|
357
|
+
const remainder = normFile === normTarget ? "" : normFile.slice(normTarget.length + 1);
|
|
358
|
+
if (!best || normTarget.length > best.matchedRoot.length) best = {
|
|
359
|
+
pattern: alias.pattern,
|
|
360
|
+
matchedRoot: normTarget,
|
|
361
|
+
remainder,
|
|
362
|
+
wildcard: true
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
} else if (normFile === normTarget || stripModuleExt(normFile) === normTarget) {
|
|
366
|
+
if (!best || normTarget.length > best.matchedRoot.length) best = {
|
|
367
|
+
pattern: alias.pattern,
|
|
368
|
+
matchedRoot: normTarget,
|
|
369
|
+
remainder: "",
|
|
370
|
+
wildcard: false
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return best;
|
|
375
|
+
}
|
|
376
|
+
function formatAliasSpecifier(match, oldSpec) {
|
|
377
|
+
if (!match.wildcard) return match.pattern;
|
|
378
|
+
const base = match.pattern.replace(/\/\*$/, "");
|
|
379
|
+
const tail = oldSpec !== void 0 && MODULE_EXT_RE.test(oldSpec) ? match.remainder : match.remainder.replace(MODULE_EXT_RE, "");
|
|
380
|
+
return tail ? `${base}/${tail}` : base;
|
|
381
|
+
}
|
|
382
|
+
function formatRelativeSpecifier(fromFile, toFile, oldSpec) {
|
|
383
|
+
const hasExt = oldSpec !== void 0 && MODULE_EXT_RE.test(oldSpec);
|
|
384
|
+
let rel = relative(dirname(fromFile), toFile).replace(WIN_SEP_RE, "/");
|
|
385
|
+
if (!hasExt) rel = rel.replace(MODULE_EXT_RE, "");
|
|
386
|
+
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
387
|
+
return rel;
|
|
388
|
+
}
|
|
389
|
+
function stripModuleExt(path) {
|
|
390
|
+
return path.replace(MODULE_EXT_RE, "");
|
|
391
|
+
}
|
|
392
|
+
function addNuxtExplicitImports(ctx) {
|
|
393
|
+
const { cwd, symbols, toAbs, fromAbs, existingChanges, noScriptError, scan } = ctx;
|
|
394
|
+
const byPath = new Map(existingChanges.map((change) => [change.path, change]));
|
|
395
|
+
const aliases = loadNuxtPathAliases(cwd);
|
|
396
|
+
const consumerSymbols = /* @__PURE__ */ new Map();
|
|
397
|
+
for (const symbol of symbols) {
|
|
398
|
+
const hits = scan(symbol, {
|
|
399
|
+
cwd,
|
|
400
|
+
kinds: ["identifier-reference"]
|
|
401
|
+
});
|
|
402
|
+
for (const hit of hits) {
|
|
403
|
+
const abs = resolve(cwd, hit.file);
|
|
404
|
+
if (!consumerSymbols.has(abs)) consumerSymbols.set(abs, /* @__PURE__ */ new Set());
|
|
405
|
+
consumerSymbols.get(abs).add(symbol);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
const out = [];
|
|
409
|
+
for (const [filePath, neededSymbols] of consumerSymbols) {
|
|
410
|
+
if (isGeneratedNuxtPath(cwd, filePath)) continue;
|
|
411
|
+
if (filePath === fromAbs || filePath === toAbs) continue;
|
|
412
|
+
let current = byPath.get(filePath)?.after ?? readFileSync(filePath, "utf8");
|
|
413
|
+
const before = byPath.get(filePath)?.before ?? current;
|
|
414
|
+
const specifier = resolveBestImportSpecifier(filePath, toAbs, aliases, "./placeholder");
|
|
415
|
+
let touched = false;
|
|
416
|
+
for (const symbol of neededSymbols) {
|
|
417
|
+
if (hasNamedImport(current, symbol)) continue;
|
|
418
|
+
const next = filePath.endsWith(".vue") ? insertVueScriptImport(current, symbol, specifier, noScriptError) : insertTopLevelImport(current, symbol, specifier);
|
|
419
|
+
if (next !== current) {
|
|
420
|
+
current = next;
|
|
421
|
+
touched = true;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
if (touched) out.push({
|
|
425
|
+
path: filePath,
|
|
426
|
+
rel: relative(cwd, filePath),
|
|
427
|
+
before,
|
|
428
|
+
after: current
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
return out;
|
|
432
|
+
}
|
|
433
|
+
function insertVueScriptImport(source, symbol, specifier, noScriptError) {
|
|
434
|
+
const match = source.match(/<script(?:\s[^>]*)?>/);
|
|
435
|
+
if (!match || match.index === void 0) throw noScriptError(symbol);
|
|
436
|
+
const insertAt = match.index + match[0].length;
|
|
437
|
+
const scriptEnd = source.indexOf("<\/script>", insertAt);
|
|
438
|
+
const scriptSource = scriptEnd >= 0 ? source.slice(insertAt, scriptEnd) : source.slice(insertAt);
|
|
439
|
+
const mergedScript = mergeNamedImport(scriptSource, symbol, specifier);
|
|
440
|
+
if (mergedScript !== scriptSource) return `${source.slice(0, insertAt)}${mergedScript}${scriptEnd >= 0 ? source.slice(scriptEnd) : ""}`;
|
|
441
|
+
const rest = source[insertAt] === "\n" ? source.slice(insertAt + 1) : source.slice(insertAt);
|
|
442
|
+
return `${source.slice(0, insertAt)}\nimport { ${symbol} } from '${specifier}'\n${rest}`;
|
|
443
|
+
}
|
|
444
|
+
function insertTopLevelImport(source, symbol, specifier) {
|
|
445
|
+
const merged = mergeNamedImport(source, symbol, specifier);
|
|
446
|
+
if (merged !== source) return merged;
|
|
447
|
+
const importLine = `import { ${symbol} } from '${specifier}'\n`;
|
|
448
|
+
if (source.startsWith("#!")) {
|
|
449
|
+
const nl = source.indexOf("\n");
|
|
450
|
+
if (nl >= 0) return `${source.slice(0, nl + 1)}${importLine}${source.slice(nl + 1)}`;
|
|
451
|
+
}
|
|
452
|
+
return `${importLine}${source}`;
|
|
453
|
+
}
|
|
454
|
+
function hasNamedImport(source, symbol) {
|
|
455
|
+
const escaped = symbol.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
456
|
+
return new RegExp(`\\bimport\\s*\\{[^}]*\\b${escaped}\\b[^}]*\\}\\s*from\\s*['"]`).test(source);
|
|
457
|
+
}
|
|
458
|
+
function mergeNamedImport(source, symbol, specifier) {
|
|
459
|
+
const spec = specifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
460
|
+
const match = new RegExp(`import\\s*\\{([^}]*)\\}\\s*from\\s*(['"])${spec}\\2`).exec(source);
|
|
461
|
+
if (!match) return source;
|
|
462
|
+
const names = match[1].split(",").map((part) => part.trim()).filter(Boolean);
|
|
463
|
+
if (names.some((name) => name === symbol || name.startsWith(`${symbol} as `))) return source;
|
|
464
|
+
const replacement = `import { ${[...names, symbol].join(", ")} } from ${match[2]}${specifier}${match[2]}`;
|
|
465
|
+
return `${source.slice(0, match.index)}${replacement}${source.slice(match.index + match[0].length)}`;
|
|
466
|
+
}
|
|
467
|
+
const EXPORT_DECL_RE = /^\s*export\s+(?:async\s+)?(?:function|class|interface|type|enum|const|let|var)\s+([A-Za-z_$][\w$]*)/gm;
|
|
468
|
+
const EXPORT_LIST_RE = /^\s*export\s*\{([^}]+)\}/gm;
|
|
469
|
+
function extractTopLevelExportNames(source) {
|
|
470
|
+
const out = /* @__PURE__ */ new Set();
|
|
471
|
+
for (const match of source.matchAll(EXPORT_DECL_RE)) out.add(match[1]);
|
|
472
|
+
for (const match of source.matchAll(EXPORT_LIST_RE)) for (const part of match[1].split(",")) {
|
|
473
|
+
const cleaned = part.trim();
|
|
474
|
+
if (!cleaned) continue;
|
|
475
|
+
const asMatch = cleaned.match(/^(?:type\s+)?[\w$]+\s+as\s+([A-Za-z_$][\w$]*)$/);
|
|
476
|
+
if (asMatch) {
|
|
477
|
+
out.add(asMatch[1]);
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
const direct = cleaned.replace(/^type\s+/, "").match(/^([A-Z_$][\w$]*)$/i);
|
|
481
|
+
if (direct) out.add(direct[1]);
|
|
482
|
+
}
|
|
483
|
+
return [...out];
|
|
484
|
+
}
|
|
485
|
+
const TS_LIKE_RE = /\.(?:tsx?|mts|cts|jsx?|mjs|cjs)$/;
|
|
486
|
+
async function finalizeVueFileRename(cwd, oldAbs, newAbs, existingChanges, autoImportScopes) {
|
|
487
|
+
const changes = [];
|
|
488
|
+
const warnings = [];
|
|
489
|
+
if (oldAbs.endsWith(".vue") && newAbs.endsWith(".vue")) {
|
|
490
|
+
const oldName = basename(oldAbs, ".vue");
|
|
491
|
+
const newName = basename(newAbs, ".vue");
|
|
492
|
+
mergeIntoChanges(changes, rewriteResolveComponentSites(cwd, oldName, newName, existingChanges, oldAbs, newAbs, warnings));
|
|
493
|
+
if (autoImportScopes.size && isInsideAutoImportScope(oldAbs, autoImportScopes) && !isInsideAutoImportScope(newAbs, autoImportScopes)) mergeIntoChanges(changes, addExplicitComponentImports(cwd, oldName, newName, newAbs, mergeView(existingChanges, changes), oldAbs));
|
|
494
|
+
return {
|
|
495
|
+
changes,
|
|
496
|
+
warnings
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
if (TS_LIKE_RE.test(oldAbs) && TS_LIKE_RE.test(newAbs) && autoImportScopes.size && isInsideAutoImportScope(oldAbs, autoImportScopes) && !isInsideAutoImportScope(newAbs, autoImportScopes)) {
|
|
500
|
+
const movedSource = readMovedSource(oldAbs, newAbs, existingChanges);
|
|
501
|
+
const symbols = movedSource ? extractTopLevelExportNames(movedSource) : [];
|
|
502
|
+
if (symbols.length) mergeIntoChanges(changes, addNuxtExplicitImports({
|
|
503
|
+
cwd,
|
|
504
|
+
symbols,
|
|
505
|
+
toAbs: newAbs,
|
|
506
|
+
fromAbs: oldAbs,
|
|
507
|
+
existingChanges: mergeView(existingChanges, changes),
|
|
508
|
+
scan,
|
|
509
|
+
noScriptError: (name) => /* @__PURE__ */ new Error(`ripast rename-file: "${name}" is auto-imported in Nuxt; moving ${basename(oldAbs)} to ${newAbs} takes it out of auto-import scope but a consumer has no <script> block to receive an explicit import. Add a <script setup> block first, or keep the file in composables/utils.`)
|
|
510
|
+
}));
|
|
511
|
+
}
|
|
512
|
+
return {
|
|
513
|
+
changes,
|
|
514
|
+
warnings
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
function readMovedSource(oldAbs, newAbs, existingChanges) {
|
|
518
|
+
const self = existingChanges.find((c) => c.path === oldAbs || c.path === newAbs);
|
|
519
|
+
if (self) return self.before;
|
|
520
|
+
try {
|
|
521
|
+
return readFileSync(oldAbs, "utf8");
|
|
522
|
+
} catch {
|
|
523
|
+
return null;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
function mergeView(a, b) {
|
|
527
|
+
const map = /* @__PURE__ */ new Map();
|
|
528
|
+
for (const c of a) map.set(c.path, c);
|
|
529
|
+
for (const c of b) map.set(c.path, c);
|
|
530
|
+
return [...map.values()];
|
|
531
|
+
}
|
|
532
|
+
function mergeIntoChanges(target, incoming) {
|
|
533
|
+
for (const change of incoming) {
|
|
534
|
+
const existing = target.find((c) => c.path === change.path);
|
|
535
|
+
if (existing) existing.after = change.after;
|
|
536
|
+
else target.push(change);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
function rewriteResolveComponentSites(cwd, oldName, newName, changes, oldAbs, newAbs, warnings) {
|
|
540
|
+
const candidates = new Set(rgFiles("resolveComponent", { cwd }));
|
|
541
|
+
if (!candidates.size) return [];
|
|
542
|
+
const byPath = new Map(changes.map((change) => [change.path, change]));
|
|
543
|
+
const escaped = escapeRe(oldName);
|
|
544
|
+
const literalRe = new RegExp(`resolveComponent\\s*\\(\\s*(['"\`])${escaped}\\1`, "g");
|
|
545
|
+
const out = [];
|
|
546
|
+
const warnFiles = [];
|
|
547
|
+
for (const path of candidates) {
|
|
548
|
+
if (path === oldAbs || path === newAbs || isGeneratedNuxtPath(cwd, path)) continue;
|
|
549
|
+
const before = byPath.get(path)?.before ?? readFileSync(path, "utf8");
|
|
550
|
+
const current = byPath.get(path)?.after ?? before;
|
|
551
|
+
literalRe.lastIndex = 0;
|
|
552
|
+
if (!literalRe.test(current)) continue;
|
|
553
|
+
warnFiles.push(relative(cwd, path));
|
|
554
|
+
if (oldName === newName) continue;
|
|
555
|
+
literalRe.lastIndex = 0;
|
|
556
|
+
const after = current.replace(literalRe, (match, quote) => match.replace(`${quote}${oldName}${quote}`, `${quote}${newName}${quote}`));
|
|
557
|
+
if (after === current) continue;
|
|
558
|
+
out.push({
|
|
559
|
+
path,
|
|
560
|
+
rel: relative(cwd, path),
|
|
561
|
+
before,
|
|
562
|
+
after
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
if (warnFiles.length) warnings.push(`rename-file: "${oldName}" is referenced via resolveComponent() in ${warnFiles.length} file(s) [${warnFiles.join(", ")}]. The component must stay globally registered for these sites to resolve (plugin app.component(...) or Nuxt components dir).`);
|
|
566
|
+
return out;
|
|
567
|
+
}
|
|
568
|
+
function addExplicitComponentImports(cwd, oldName, newName, newAbs, changes, oldAbs) {
|
|
569
|
+
const tokens = new Set([
|
|
570
|
+
oldName,
|
|
571
|
+
newName,
|
|
572
|
+
hyphenateVueName(oldName),
|
|
573
|
+
hyphenateVueName(newName)
|
|
574
|
+
]);
|
|
575
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
576
|
+
for (const token of tokens) for (const path of rgFiles(token, {
|
|
577
|
+
cwd,
|
|
578
|
+
glob: "*.vue"
|
|
579
|
+
})) candidates.add(path);
|
|
580
|
+
if (!candidates.size) return [];
|
|
581
|
+
const aliases = loadNuxtPathAliases(cwd);
|
|
582
|
+
const byPath = new Map(changes.map((change) => [change.path, change]));
|
|
583
|
+
const tagRe = new RegExp(`<\\/?(?:${escapeRe(newName)}|${escapeRe(hyphenateVueName(newName))})(?=[\\s/>])`);
|
|
584
|
+
const out = [];
|
|
585
|
+
for (const path of candidates) {
|
|
586
|
+
if (path === oldAbs || path === newAbs || isGeneratedNuxtPath(cwd, path)) continue;
|
|
587
|
+
const before = byPath.get(path)?.before ?? readFileSync(path, "utf8");
|
|
588
|
+
const current = byPath.get(path)?.after ?? before;
|
|
589
|
+
if (!tagRe.test(current)) continue;
|
|
590
|
+
if (hasDefaultImportFromVue(current, newName)) continue;
|
|
591
|
+
const after = insertVueComponentImport(current, newName, resolveBestImportSpecifier(path, newAbs, aliases, "./placeholder.vue"));
|
|
592
|
+
if (after === current) continue;
|
|
593
|
+
out.push({
|
|
594
|
+
path,
|
|
595
|
+
rel: relative(cwd, path),
|
|
596
|
+
before,
|
|
597
|
+
after
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
return out;
|
|
601
|
+
}
|
|
602
|
+
function escapeRe(s) {
|
|
603
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
604
|
+
}
|
|
605
|
+
function hasDefaultImportFromVue(source, name) {
|
|
606
|
+
return new RegExp(`\\bimport\\s+${escapeRe(name)}\\s+from\\s+['"\`][^'"\`]+\\.vue['"\`]`).test(source);
|
|
607
|
+
}
|
|
608
|
+
function insertVueComponentImport(source, name, specifier) {
|
|
609
|
+
const match = source.match(/<script(?:\s[^>]*)?>/);
|
|
610
|
+
if (!match || match.index === void 0) throw new Error(`ripast rename-file: "${name}" is auto-imported in Nuxt; the new path falls outside auto-import scope but a consumer has no <script> block to receive an explicit import. Add a <script setup> block first.`);
|
|
611
|
+
const insertAt = match.index + match[0].length;
|
|
612
|
+
const importLine = `\nimport ${name} from '${specifier}'`;
|
|
613
|
+
if (source.slice(insertAt, insertAt + 1) === "\n") return `${source.slice(0, insertAt)}${importLine}${source.slice(insertAt)}`;
|
|
614
|
+
return `${source.slice(0, insertAt)}${importLine}\n${source.slice(insertAt)}`;
|
|
615
|
+
}
|
|
276
616
|
const adapter = {
|
|
277
617
|
name: "vue",
|
|
278
618
|
hasFilesContaining: hasVueFilesContaining,
|
|
@@ -292,6 +632,15 @@ const adapter = {
|
|
|
292
632
|
autoImportScopes(cwd) {
|
|
293
633
|
if (!isNuxtProject(cwd)) return /* @__PURE__ */ new Set();
|
|
294
634
|
return nuxtAutoImportScopes(cwd);
|
|
635
|
+
},
|
|
636
|
+
isGeneratedPath: isGeneratedNuxtPath,
|
|
637
|
+
filterGeneratedChanges: removeGeneratedNuxtChanges,
|
|
638
|
+
addExplicitImports: (ctx) => addNuxtExplicitImports({
|
|
639
|
+
...ctx,
|
|
640
|
+
scan
|
|
641
|
+
}),
|
|
642
|
+
async finalizeFileRename(cwd, oldAbs, newAbs, existingChanges) {
|
|
643
|
+
return finalizeVueFileRename(cwd, oldAbs, newAbs, existingChanges, isNuxtProject(cwd) ? nuxtAutoImportScopes(cwd) : /* @__PURE__ */ new Set());
|
|
295
644
|
}
|
|
296
645
|
};
|
|
297
646
|
const DEFAULT_NUXT_AUTO_IMPORT_DIRS = [
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ripast/vue",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.1",
|
|
5
5
|
"description": "Vue (and Nuxt) framework adapter for ripast. Provides Volar/Vue Language Service-backed rename, move, and template rewriting for .vue SFCs.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Harlan Wilton",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"typescript": ">=5.4",
|
|
45
|
-
"@ripast/core": "0.
|
|
45
|
+
"@ripast/core": "0.2.1"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@volar/language-service": "^2.4.28",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"vscode-uri": "^3.1.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@ripast/core": "0.
|
|
58
|
+
"@ripast/core": "0.2.1"
|
|
59
59
|
},
|
|
60
60
|
"scripts": {
|
|
61
61
|
"build": "obuild",
|