This commit is contained in:
2024-02-07 01:33:07 -05:00
commit c1af19d441
4088 changed files with 1260170 additions and 0 deletions

View File

@ -0,0 +1,4 @@
import { VirtualFile } from '@volar/language-core';
import type { Sfc, VueLanguagePlugin } from '../types';
export declare function computedFiles(plugins: ReturnType<VueLanguagePlugin>[], fileName: string, sfc: Sfc, codegenStack: boolean): () => VirtualFile[];
//# sourceMappingURL=computedFiles.d.ts.map

View File

@ -0,0 +1,204 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.computedFiles = void 0;
const source_map_1 = require("@volar/source-map");
const muggle = require("muggle-string");
const embeddedFile_1 = require("./embeddedFile");
const computeds_1 = require("computeds");
function computedFiles(plugins, fileName, sfc, codegenStack) {
const nameToBlock = (0, computeds_1.computed)(() => {
const blocks = {};
if (sfc.template) {
blocks[sfc.template.name] = sfc.template;
}
if (sfc.script) {
blocks[sfc.script.name] = sfc.script;
}
if (sfc.scriptSetup) {
blocks[sfc.scriptSetup.name] = sfc.scriptSetup;
}
for (const block of sfc.styles) {
blocks[block.name] = block;
}
for (const block of sfc.customBlocks) {
blocks[block.name] = block;
}
return blocks;
});
const pluginsResult = plugins.map(plugin => compiledPluginFiles(plugins, plugin, fileName, sfc, nameToBlock, codegenStack));
const flatResult = (0, computeds_1.computed)(() => pluginsResult.map(r => r()).flat());
const structuredResult = (0, computeds_1.computed)(() => {
const embeddedFiles = [];
let remain = [...flatResult()];
while (remain.length) {
const beforeLength = remain.length;
consumeRemain();
if (beforeLength === remain.length) {
break;
}
}
for (const { file, snapshot, mappings, codegenStacks } of remain) {
embeddedFiles.push({
...file,
snapshot,
mappings,
codegenStacks,
embeddedFiles: [],
});
console.error('Unable to resolve embedded: ' + file.parentFileName + ' -> ' + file.fileName);
}
return embeddedFiles;
function consumeRemain() {
for (let i = remain.length - 1; i >= 0; i--) {
const { file, snapshot, mappings, codegenStacks } = remain[i];
if (!file.parentFileName) {
embeddedFiles.push({
...file,
snapshot,
mappings,
codegenStacks,
embeddedFiles: [],
});
remain.splice(i, 1);
}
else {
const parent = findParentStructure(file.parentFileName, embeddedFiles);
if (parent) {
parent.embeddedFiles.push({
...file,
snapshot,
mappings,
codegenStacks,
embeddedFiles: [],
});
remain.splice(i, 1);
}
}
}
}
function findParentStructure(fileName, current) {
for (const child of current) {
if (child.fileName === fileName) {
return child;
}
let parent = findParentStructure(fileName, child.embeddedFiles);
if (parent) {
return parent;
}
}
}
});
return structuredResult;
}
exports.computedFiles = computedFiles;
function compiledPluginFiles(plugins, plugin, fileName, sfc, nameToBlock, codegenStack) {
const embeddedFiles = {};
const files = (0, computeds_1.computed)(() => {
try {
if (!plugin.getEmbeddedFileNames) {
return Object.values(embeddedFiles);
}
const embeddedFileNames = plugin.getEmbeddedFileNames(fileName, sfc);
for (const oldFileName of Object.keys(embeddedFiles)) {
if (!embeddedFileNames.includes(oldFileName)) {
delete embeddedFiles[oldFileName];
}
}
for (const embeddedFileName of embeddedFileNames) {
if (!embeddedFiles[embeddedFileName]) {
embeddedFiles[embeddedFileName] = (0, computeds_1.computed)(() => {
const [content, stacks] = codegenStack ? muggle.track([]) : [[], []];
const file = new embeddedFile_1.VueEmbeddedFile(embeddedFileName, content, stacks);
for (const plugin of plugins) {
if (!plugin.resolveEmbeddedFile) {
continue;
}
try {
plugin.resolveEmbeddedFile(fileName, sfc, file);
}
catch (e) {
console.error(e);
}
}
const newText = (0, source_map_1.toString)(file.content);
const changeRanges = new Map();
const snapshot = {
getText: (start, end) => newText.slice(start, end),
getLength: () => newText.length,
getChangeRange(oldSnapshot) {
if (!changeRanges.has(oldSnapshot)) {
changeRanges.set(oldSnapshot, undefined);
const oldText = oldSnapshot.getText(0, oldSnapshot.getLength());
const changeRange = fullDiffTextChangeRange(oldText, newText);
if (changeRange) {
changeRanges.set(oldSnapshot, changeRange);
}
}
return changeRanges.get(oldSnapshot);
},
};
return {
file,
snapshot,
};
});
}
}
}
catch (e) {
console.error(e);
}
return Object.values(embeddedFiles);
});
return (0, computeds_1.computed)(() => {
return files().map(_file => {
const { file, snapshot } = _file();
const mappings = (0, source_map_1.buildMappings)(file.content);
for (const mapping of mappings) {
if (mapping.source !== undefined) {
const block = nameToBlock()[mapping.source];
if (block) {
mapping.sourceRange = [
mapping.sourceRange[0] + block.startTagEnd,
mapping.sourceRange[1] + block.startTagEnd,
];
}
else {
// ignore
}
mapping.source = undefined;
}
}
return {
file,
snapshot,
mappings,
codegenStacks: (0, source_map_1.buildStacks)(file.content, file.contentStacks),
};
});
});
}
function fullDiffTextChangeRange(oldText, newText) {
for (let start = 0; start < oldText.length && start < newText.length; start++) {
if (oldText[start] !== newText[start]) {
let end = oldText.length;
for (let i = 0; i < oldText.length - start && i < newText.length - start; i++) {
if (oldText[oldText.length - i - 1] !== newText[newText.length - i - 1]) {
break;
}
end--;
}
let length = end - start;
let newLength = length + (newText.length - oldText.length);
if (newLength < 0) {
length -= newLength;
newLength = 0;
}
return {
span: { start, length },
newLength,
};
}
}
}
//# sourceMappingURL=computedFiles.js.map

View File

@ -0,0 +1,6 @@
import { FileRangeCapabilities } from '@volar/language-core';
import { Mapping } from '@volar/source-map';
import type * as ts from 'typescript/lib/tsserverlibrary';
import { Sfc } from '../types';
export declare function computedMappings(snapshot: () => ts.IScriptSnapshot, sfc: Sfc): () => Mapping<FileRangeCapabilities>[];
//# sourceMappingURL=computedMappings.d.ts.map

View File

@ -0,0 +1,39 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.computedMappings = void 0;
const language_core_1 = require("@volar/language-core");
const muggle = require("muggle-string");
const computeds_1 = require("computeds");
function computedMappings(snapshot, sfc) {
return (0, computeds_1.computed)(() => {
const str = [[snapshot().getText(0, snapshot().getLength()), undefined, 0, language_core_1.FileRangeCapabilities.full]];
for (const block of [
sfc.script,
sfc.scriptSetup,
sfc.template,
...sfc.styles,
...sfc.customBlocks,
]) {
if (block) {
muggle.replaceSourceRange(str, undefined, block.startTagEnd, block.endTagStart, [
block.content,
undefined,
block.startTagEnd,
{},
]);
}
}
return str.map((m) => {
const text = m[0];
const start = m[2];
const end = start + text.length;
return {
sourceRange: [start, end],
generatedRange: [start, end],
data: m[3],
};
});
});
}
exports.computedMappings = computedMappings;
//# sourceMappingURL=computedMappings.js.map

View File

@ -0,0 +1,5 @@
import type { SFCParseResult } from '@vue/compiler-sfc';
import type * as ts from 'typescript/lib/tsserverlibrary';
import { Sfc, VueLanguagePlugin } from '../types';
export declare function computedSfc(ts: typeof import('typescript/lib/tsserverlibrary'), plugins: ReturnType<VueLanguagePlugin>[], fileName: string, snapshot: () => ts.IScriptSnapshot, parsed: () => SFCParseResult | undefined): Sfc;
//# sourceMappingURL=computedSfc.d.ts.map

View File

@ -0,0 +1,197 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.computedSfc = void 0;
const parseCssClassNames_1 = require("../utils/parseCssClassNames");
const parseCssVars_1 = require("../utils/parseCssVars");
const computeds_1 = require("computeds");
function computedSfc(ts, plugins, fileName, snapshot, parsed) {
const untrackedSnapshot = () => {
(0, computeds_1.pauseTracking)();
const res = snapshot();
(0, computeds_1.resetTracking)();
return res;
};
const template = computedNullableSfcBlock('template', 'html', (0, computeds_1.computed)(() => parsed()?.descriptor.template ?? undefined), (_block, base) => {
const compiledAst = computedTemplateAst(base);
return mergeObject(base, {
get ast() { return compiledAst()?.ast; },
get errors() { return compiledAst()?.errors; },
get warnings() { return compiledAst()?.warnings; },
});
});
const script = computedNullableSfcBlock('script', 'js', (0, computeds_1.computed)(() => parsed()?.descriptor.script ?? undefined), (block, base) => {
const src = (0, computeds_1.computed)(() => block().src);
const srcOffset = (0, computeds_1.computed)(() => {
const _src = src();
return _src ? untrackedSnapshot().getText(0, base.startTagEnd).lastIndexOf(_src) - base.startTagEnd : -1;
});
const ast = (0, computeds_1.computed)(() => ts.createSourceFile(fileName + '.' + base.lang, base.content, ts.ScriptTarget.Latest));
return mergeObject(base, {
get src() { return src(); },
get srcOffset() { return srcOffset(); },
get ast() { return ast(); },
});
});
const scriptSetup = computedNullableSfcBlock('scriptSetup', 'js', (0, computeds_1.computed)(() => parsed()?.descriptor.scriptSetup ?? undefined), (block, base) => {
const generic = (0, computeds_1.computed)(() => {
const _block = block();
return typeof _block.attrs.generic === 'string' ? _block.attrs.generic : undefined;
});
const genericOffset = (0, computeds_1.computed)(() => {
const _generic = generic();
return _generic !== undefined ? untrackedSnapshot().getText(0, base.startTagEnd).lastIndexOf(_generic) - base.startTagEnd : -1;
});
const ast = (0, computeds_1.computed)(() => ts.createSourceFile(fileName + '.' + base.lang, base.content, ts.ScriptTarget.Latest));
return mergeObject(base, {
get generic() { return generic(); },
get genericOffset() { return genericOffset(); },
get ast() { return ast(); },
});
});
const styles = (0, computeds_1.computedArray)((0, computeds_1.computed)(() => parsed()?.descriptor.styles ?? []), (block, i) => {
const base = computedSfcBlock('style_' + i, 'css', block);
const module = (0, computeds_1.computed)(() => typeof block().module === 'string' ? block().module : block().module ? '$style' : undefined);
const scoped = (0, computeds_1.computed)(() => !!block().scoped);
const cssVars = (0, computeds_1.computed)(() => [...(0, parseCssVars_1.parseCssVars)(base.content)]);
const classNames = (0, computeds_1.computed)(() => [...(0, parseCssClassNames_1.parseCssClassNames)(base.content)]);
return (0, computeds_1.computed)(() => mergeObject(base, {
get module() { return module(); },
get scoped() { return scoped(); },
get cssVars() { return cssVars(); },
get classNames() { return classNames(); },
}));
});
const customBlocks = (0, computeds_1.computedArray)((0, computeds_1.computed)(() => parsed()?.descriptor.customBlocks ?? []), (block, i) => {
const base = computedSfcBlock('customBlock_' + i, 'txt', block);
const type = (0, computeds_1.computed)(() => block().type);
return (0, computeds_1.computed)(() => mergeObject(base, {
get type() { return type(); },
}));
});
return {
get template() { return template(); },
get script() { return script(); },
get scriptSetup() { return scriptSetup(); },
get styles() { return styles; },
get customBlocks() { return customBlocks; },
get templateAst() { return template()?.ast; },
get scriptAst() { return script()?.ast; },
get scriptSetupAst() { return scriptSetup()?.ast; },
};
function computedTemplateAst(base) {
let cache;
return (0, computeds_1.computed)(() => {
if (cache?.template === base.content) {
return {
errors: [],
warnings: [],
ast: cache?.result.ast,
};
}
// incremental update
if (cache?.plugin.updateSFCTemplate) {
const change = untrackedSnapshot().getChangeRange(cache.snapshot);
if (change) {
(0, computeds_1.pauseTracking)();
const templateOffset = base.startTagEnd;
(0, computeds_1.resetTracking)();
const newText = untrackedSnapshot().getText(change.span.start, change.span.start + change.newLength);
const newResult = cache.plugin.updateSFCTemplate(cache.result, {
start: change.span.start - templateOffset,
end: change.span.start + change.span.length - templateOffset,
newText,
});
if (newResult) {
cache.template = base.content;
cache.snapshot = untrackedSnapshot();
cache.result = newResult;
return {
errors: [],
warnings: [],
ast: newResult.ast,
};
}
}
}
const errors = [];
const warnings = [];
let options = {
onError: (err) => errors.push(err),
onWarn: (err) => warnings.push(err),
expressionPlugins: ['typescript'],
};
for (const plugin of plugins) {
if (plugin.resolveTemplateCompilerOptions) {
options = plugin.resolveTemplateCompilerOptions(options);
}
}
for (const plugin of plugins) {
let result;
try {
result = plugin.compileSFCTemplate?.(base.lang, base.content, options);
}
catch (e) {
const err = e;
errors.push(err);
}
if (result || errors.length) {
if (result && !errors.length && !warnings.length) {
cache = {
template: base.content,
snapshot: untrackedSnapshot(),
result: result,
plugin,
};
}
else {
cache = undefined;
}
return {
errors,
warnings,
ast: result?.ast,
};
}
}
return {
errors,
warnings,
ast: undefined,
};
});
}
function computedNullableSfcBlock(name, defaultLang, block, resolve) {
const hasBlock = (0, computeds_1.computed)(() => !!block());
return (0, computeds_1.computed)(() => {
if (!hasBlock()) {
return;
}
const _block = (0, computeds_1.computed)(() => block());
return resolve(_block, computedSfcBlock(name, defaultLang, _block));
});
}
function computedSfcBlock(name, defaultLang, block) {
const lang = (0, computeds_1.computed)(() => block().lang ?? defaultLang);
const attrs = (0, computeds_1.computed)(() => block().attrs); // TODO: computed it
const content = (0, computeds_1.computed)(() => block().content);
const startTagEnd = (0, computeds_1.computed)(() => block().loc.start.offset);
const endTagStart = (0, computeds_1.computed)(() => block().loc.end.offset);
const start = (0, computeds_1.computed)(() => untrackedSnapshot().getText(0, startTagEnd()).lastIndexOf('<' + block().type));
const end = (0, computeds_1.computed)(() => endTagStart() + untrackedSnapshot().getText(endTagStart(), untrackedSnapshot().getLength()).indexOf('>') + 1);
return {
name,
get lang() { return lang(); },
get attrs() { return attrs(); },
get content() { return content(); },
get startTagEnd() { return startTagEnd(); },
get endTagStart() { return endTagStart(); },
get start() { return start(); },
get end() { return end(); },
};
}
}
exports.computedSfc = computedSfc;
function mergeObject(a, b) {
return Object.defineProperties(a, Object.getOwnPropertyDescriptors(b));
}
//# sourceMappingURL=computedSfc.js.map

View File

@ -0,0 +1,5 @@
import type { SFCParseResult } from '@vue/compiler-sfc';
import type * as ts from 'typescript/lib/tsserverlibrary';
import { VueLanguagePlugin } from '../types';
export declare function computedVueSfc(plugins: ReturnType<VueLanguagePlugin>[], fileName: string, snapshot: () => ts.IScriptSnapshot): () => SFCParseResult | undefined;
//# sourceMappingURL=computedVueSfc.d.ts.map

View File

@ -0,0 +1,41 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.computedVueSfc = void 0;
const computeds_1 = require("computeds");
function computedVueSfc(plugins, fileName, snapshot) {
let cache;
return (0, computeds_1.computed)(() => {
// incremental update
if (cache?.plugin.updateSFC) {
const change = snapshot().getChangeRange(cache.snapshot);
if (change) {
const newSfc = cache.plugin.updateSFC(cache.sfc, {
start: change.span.start,
end: change.span.start + change.span.length,
newText: snapshot().getText(change.span.start, change.span.start + change.newLength),
});
if (newSfc) {
cache.snapshot = snapshot();
// force dirty
cache.sfc = JSON.parse(JSON.stringify(newSfc));
return cache.sfc;
}
}
}
for (const plugin of plugins) {
const sfc = plugin.parseSFC?.(fileName, snapshot().getText(0, snapshot().getLength()));
if (sfc) {
if (!sfc.errors.length) {
cache = {
snapshot: snapshot(),
sfc,
plugin,
};
}
return sfc;
}
}
});
}
exports.computedVueSfc = computedVueSfc;
//# sourceMappingURL=computedVueSfc.js.map

View File

@ -0,0 +1,13 @@
import { FileCapabilities, FileKind, FileRangeCapabilities, MirrorBehaviorCapabilities } from '@volar/language-core';
import { Mapping, Segment, StackNode } from '@volar/source-map';
export declare class VueEmbeddedFile {
fileName: string;
content: Segment<FileRangeCapabilities>[];
contentStacks: StackNode[];
parentFileName?: string;
kind: FileKind;
capabilities: FileCapabilities;
mirrorBehaviorMappings: Mapping<[MirrorBehaviorCapabilities, MirrorBehaviorCapabilities]>[];
constructor(fileName: string, content: Segment<FileRangeCapabilities>[], contentStacks: StackNode[]);
}
//# sourceMappingURL=embeddedFile.d.ts.map

View File

@ -0,0 +1,16 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.VueEmbeddedFile = void 0;
const language_core_1 = require("@volar/language-core");
class VueEmbeddedFile {
constructor(fileName, content, contentStacks) {
this.fileName = fileName;
this.content = content;
this.contentStacks = contentStacks;
this.kind = language_core_1.FileKind.TextFile;
this.capabilities = {};
this.mirrorBehaviorMappings = [];
}
}
exports.VueEmbeddedFile = VueEmbeddedFile;
//# sourceMappingURL=embeddedFile.js.map

View File

@ -0,0 +1,28 @@
import { FileCapabilities, FileKind, VirtualFile } from '@volar/language-core';
import { Stack } from '@volar/source-map';
import type * as ts from 'typescript/lib/tsserverlibrary';
import { VueCompilerOptions, VueLanguagePlugin } from '../types';
import { Signal } from 'computeds';
export declare class VueFile implements VirtualFile {
fileName: string;
initSnapshot: ts.IScriptSnapshot;
vueCompilerOptions: VueCompilerOptions;
plugins: ReturnType<VueLanguagePlugin>[];
ts: typeof import('typescript/lib/tsserverlibrary');
codegenStack: boolean;
_snapshot: Signal<ts.IScriptSnapshot>;
getVueSfc: () => import("@vue/compiler-sfc").SFCParseResult | undefined;
sfc: import("../types").Sfc;
getMappings: () => import("@volar/source-map").Mapping<import("@volar/language-core").FileRangeCapabilities>[];
getEmbeddedFiles: () => VirtualFile[];
capabilities: FileCapabilities;
kind: FileKind;
codegenStacks: Stack[];
get embeddedFiles(): VirtualFile[];
get mainScriptName(): string;
get snapshot(): ts.IScriptSnapshot;
get mappings(): import("@volar/source-map").Mapping<import("@volar/language-core").FileRangeCapabilities>[];
constructor(fileName: string, initSnapshot: ts.IScriptSnapshot, vueCompilerOptions: VueCompilerOptions, plugins: ReturnType<VueLanguagePlugin>[], ts: typeof import('typescript/lib/tsserverlibrary'), codegenStack: boolean);
update(newSnapshot: ts.IScriptSnapshot): void;
}
//# sourceMappingURL=vueFile.d.ts.map

View File

@ -0,0 +1,53 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.VueFile = void 0;
const language_core_1 = require("@volar/language-core");
const computedFiles_1 = require("./computedFiles");
const computedMappings_1 = require("./computedMappings");
const computedSfc_1 = require("./computedSfc");
const computedVueSfc_1 = require("./computedVueSfc");
const computeds_1 = require("computeds");
const jsxReg = /^\.(js|ts)x?$/;
class VueFile {
get embeddedFiles() {
return this.getEmbeddedFiles();
}
get mainScriptName() {
let res = '';
(0, language_core_1.forEachEmbeddedFile)(this, file => {
if (file.kind === language_core_1.FileKind.TypeScriptHostFile && file.fileName.replace(this.fileName, '').match(jsxReg)) {
res = file.fileName;
}
});
return res;
}
get snapshot() {
return this._snapshot();
}
get mappings() {
return this.getMappings();
}
constructor(fileName, initSnapshot, vueCompilerOptions, plugins, ts, codegenStack) {
this.fileName = fileName;
this.initSnapshot = initSnapshot;
this.vueCompilerOptions = vueCompilerOptions;
this.plugins = plugins;
this.ts = ts;
this.codegenStack = codegenStack;
// computeds
this.getVueSfc = (0, computedVueSfc_1.computedVueSfc)(this.plugins, this.fileName, () => this._snapshot());
this.sfc = (0, computedSfc_1.computedSfc)(this.ts, this.plugins, this.fileName, () => this._snapshot(), this.getVueSfc);
this.getMappings = (0, computedMappings_1.computedMappings)(() => this._snapshot(), this.sfc);
this.getEmbeddedFiles = (0, computedFiles_1.computedFiles)(this.plugins, this.fileName, this.sfc, this.codegenStack);
// others
this.capabilities = language_core_1.FileCapabilities.full;
this.kind = language_core_1.FileKind.TextFile;
this.codegenStacks = [];
this._snapshot = (0, computeds_1.signal)(initSnapshot);
}
update(newSnapshot) {
this._snapshot.set(newSnapshot);
}
}
exports.VueFile = VueFile;
//# sourceMappingURL=vueFile.js.map