plaxtony
Version:
Static code analysis of SC2 Galaxy Script
226 lines • 8.84 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Store = exports.S2WorkspaceWatcher = exports.WorkspaceWatcher = exports.IndexedDocument = exports.openSourceFilesInLocation = exports.createTextDocumentFromUri = exports.readDocumentFile = exports.createTextDocumentFromFs = exports.createTextDocument = void 0;
const parser_1 = require("../compiler/parser");
const s2meta_1 = require("./s2meta");
const binder_1 = require("../compiler/binder");
const archive_1 = require("../sc2mod/archive");
const lsp = require("vscode-languageserver");
const vscode_languageserver_textdocument_1 = require("vscode-languageserver-textdocument");
const path = require("path");
const fs = require("fs-extra");
const glob = require("fast-glob");
const vscode_uri_1 = require("vscode-uri");
const checker_1 = require("../compiler/checker");
function createTextDocument(uri, text) {
return vscode_languageserver_textdocument_1.TextDocument.create(uri, 'galaxy', 0, text);
}
exports.createTextDocument = createTextDocument;
function createTextDocumentFromFs(filepath) {
filepath = path.resolve(filepath);
return createTextDocument(vscode_uri_1.default.file(filepath).toString(), fs.readFileSync(filepath, 'utf8'));
}
exports.createTextDocumentFromFs = createTextDocumentFromFs;
async function readDocumentFile(fsPath) {
return createTextDocument(vscode_uri_1.default.file(fsPath).toString(), await fs.readFile(fsPath, 'utf8'));
}
exports.readDocumentFile = readDocumentFile;
function createTextDocumentFromUri(uri) {
return createTextDocument(uri, fs.readFileSync(vscode_uri_1.default.parse(uri).fsPath, 'utf8'));
}
exports.createTextDocumentFromUri = createTextDocumentFromUri;
async function* openSourceFilesInLocation(...srcFolders) {
const workspaceFolders = await Promise.all(srcFolders.map(async (folder) => {
return {
folder,
galaxyFiles: await glob('**/*.galaxy', {
cwd: folder,
absolute: true,
caseSensitiveMatch: false,
onlyFiles: true,
objectMode: false,
})
};
}));
for (const wsFolder of workspaceFolders) {
for (const wsFile of wsFolder.galaxyFiles) {
yield await readDocumentFile(wsFile);
}
}
}
exports.openSourceFilesInLocation = openSourceFilesInLocation;
class IndexedDocument {
}
exports.IndexedDocument = IndexedDocument;
class WorkspaceWatcher {
constructor(...folders) {
this._onDidOpen = new lsp.Emitter();
this.folders = folders;
}
get onDidOpen() {
return this._onDidOpen.event;
}
}
exports.WorkspaceWatcher = WorkspaceWatcher;
class S2WorkspaceWatcher extends WorkspaceWatcher {
constructor(workspacePath, modSources) {
super(workspacePath);
this.modSources = [];
this.modSources = modSources;
this._onDidOpenS2Workspace = new lsp.Emitter();
}
get onDidOpenS2Archive() {
return this._onDidOpenS2Workspace.event;
}
async watch() {
const rootArchive = new archive_1.SC2Archive(path.basename(this.folders[0]), this.folders[0]);
const workspace = await archive_1.openArchiveWorkspace(rootArchive, this.modSources);
for (const modArchive of workspace.dependencies) {
for (const extSrc of await modArchive.findFiles('**/*.galaxy')) {
this._onDidOpen.fire({ document: createTextDocumentFromFs(path.join(modArchive.directory, extSrc)) });
}
}
for (const extSrc of await rootArchive.findFiles('**/*.galaxy')) {
this._onDidOpen.fire({ document: createTextDocumentFromFs(path.join(rootArchive.directory, extSrc)) });
}
this._onDidOpenS2Workspace.fire({
src: this.folders[0],
workspace: workspace,
});
}
}
exports.S2WorkspaceWatcher = S2WorkspaceWatcher;
class Store {
constructor(opts = {}) {
this.documents = new Map();
this.qualifiedDocuments = new Map();
this.openDocuments = new Set();
this.parser = opts.parser ? opts.parser : new parser_1.Parser();
}
clear() {
for (const key of this.documents.keys()) {
if (this.openDocuments.has(key))
continue;
this.removeDocument(key);
}
this.s2workspace = void 0;
this.s2metadata = void 0;
}
removeQualifiedDocument(qsFile) {
const qDocMap = this.qualifiedDocuments.get(qsFile.s2meta.docName.toLowerCase());
if (qDocMap) {
qDocMap.delete(qsFile.fileName);
if (!qDocMap.size) {
this.qualifiedDocuments.delete(qsFile.s2meta.docName.toLowerCase());
}
}
}
requalifyFile(qsFile) {
if (qsFile.s2meta) {
this.removeQualifiedDocument(qsFile);
}
const fsPath = vscode_uri_1.default.parse(qsFile.fileName).fsPath;
let s2file;
if (this.s2workspace) {
s2file = this.s2workspace.resolvePath(fsPath);
}
else if (this.rootPath) {
const commonBase = fsPath.toLowerCase().startsWith(this.rootPath.toLowerCase() + path.sep);
if (commonBase) {
const relativePath = fsPath.substring(this.rootPath.length + 1).toLowerCase();
s2file = {
fsPath: fsPath,
relativePath: relativePath,
archiveRelpath: relativePath,
priority: 0,
};
}
}
if (s2file) {
qsFile.s2meta = {
file: s2file,
docName: s2file.relativePath.replace(/\.galaxy$/, ''),
};
let qDocMap = this.qualifiedDocuments.get(qsFile.s2meta.docName.toLowerCase());
if (!qDocMap) {
qDocMap = new Map();
this.qualifiedDocuments.set(qsFile.s2meta.docName.toLowerCase(), qDocMap);
}
if (qDocMap.size > 1) {
const tmpDocs = Array.from(qDocMap).sort((a, b) => a[1].s2meta.file.priority - b[1].s2meta.file.priority);
qDocMap.clear();
for (const [k, v] of tmpDocs) {
qDocMap.set(k, v);
}
}
qDocMap.set(qsFile.fileName, qsFile);
}
else {
qsFile.s2meta = void 0;
}
}
removeDocument(documentUri) {
const currSorceFile = this.documents.get(documentUri);
if (!currSorceFile)
return;
binder_1.unbindSourceFile(currSorceFile, this);
if (currSorceFile.s2meta) {
this.removeQualifiedDocument(currSorceFile);
}
this.documents.delete(documentUri);
}
updateDocument(document, check = false) {
if (this.documents.has(document.uri)) {
const currSorceFile = this.documents.get(document.uri);
if (document.getText().length === currSorceFile.text.length && document.getText().valueOf() === currSorceFile.text.valueOf()) {
return;
}
this.removeDocument(document.uri);
}
const sourceFile = this.parser.parseFile(document.uri, document.getText());
this.documents.set(document.uri, sourceFile);
this.requalifyFile(sourceFile);
if (check) {
const checker = new checker_1.TypeChecker(this);
sourceFile.additionalSyntacticDiagnostics = checker.checkSourceFile(sourceFile, true);
}
else {
binder_1.bindSourceFile(sourceFile, this);
}
}
async updateS2Workspace(workspace) {
this.s2workspace = workspace;
this.qualifiedDocuments.clear();
for (const qsFile of this.documents.values()) {
this.requalifyFile(qsFile);
}
}
async rebuildS2Metadata(metadataCfg = {
loadLevel: 'Default',
localization: 'enUS',
}, dataCatalogConfig = {
enabled: true,
}) {
this.s2metadata = new s2meta_1.S2WorkspaceMetadata(this.s2workspace, metadataCfg, dataCatalogConfig);
await this.s2metadata.build();
}
isUriInWorkspace(documentUri) {
const qsFile = this.documents.get(documentUri);
if (qsFile && qsFile.s2meta)
return true;
const fsPath = vscode_uri_1.default.parse(documentUri).fsPath;
const s2file = this.s2workspace.resolvePath(fsPath);
if (s2file)
return true;
return false;
}
resolveGlobalSymbol(name) {
for (const doc of this.documents.values()) {
if (doc.symbol.members.has(name)) {
return doc.symbol.members.get(name);
}
}
}
}
exports.Store = Store;
//# sourceMappingURL=store.js.map