diff --git a/languages/qmljs/duchain/frameworks/nodejs.cpp b/languages/qmljs/duchain/frameworks/nodejs.cpp index 4d3e1f52e7..419be79ed8 100644 --- a/languages/qmljs/duchain/frameworks/nodejs.cpp +++ b/languages/qmljs/duchain/frameworks/nodejs.cpp @@ -1,214 +1,215 @@ /* * This file is part of qmljs, the QML/JS language support plugin for KDevelop * Copyright (c) 2014 Denis Steckelmacher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "nodejs.h" #include "../helper.h" #include "../parsesession.h" #include #include #include #include #include #include #include #include using namespace KDevelop; namespace QmlJS { NodeJS::NodeJS() { } NodeJS& NodeJS::instance() { static NodeJS* i = nullptr; if (!i) { i = new NodeJS(); } return *i; } void NodeJS::initialize(DeclarationBuilder* builder) { QMutexLocker lock(&m_mutex); // Create "module", a structure that may contain "exports" if the module // refers to module.exports createObject(QStringLiteral("module"), 1, builder); // Create "exports", that can also contain the exported symbols of the module createObject(QStringLiteral("exports"), 2, builder); } void NodeJS::createObject(const QString& name, int index, DeclarationBuilder* builder) { Identifier identifier(name); StructureType::Ptr type(new StructureType); Declaration* decl = builder->openDeclaration(identifier, RangeInRevision()); type->setDeclaration(decl); decl->setAlwaysForceDirect(true); decl->setKind(Declaration::Type); // Not exactly what the user would expect, but this ensures that QmlJS::getInternalContext does not recurse infinitely decl->setInternalContext(builder->openContext( (QmlJS::AST::Node*)nullptr + index, // Index is used to disambiguate the contexts. "node" is never dereferenced and is only stored in a hash table RangeInRevision(), DUContext::Class, QualifiedIdentifier(identifier) )); builder->closeContext(); builder->openType(type); builder->closeAndAssignType(); } DeclarationPointer NodeJS::moduleExports(const QString& moduleName, const IndexedString& url) { QString urlStr = url.str(); QString fileName = moduleFileName(moduleName, urlStr); DeclarationPointer exports; if (fileName.isEmpty() || urlStr.contains(QLatin1String("__builtin_ecmascript.js")) || urlStr == fileName) { return exports; } ReferencedTopDUContext topContext = ParseSession::contextOfFile(fileName, url, 0); DUChainReadLocker lock; if (topContext) { static const QualifiedIdentifier idModule(QStringLiteral("module")); static const QualifiedIdentifier idExports(QStringLiteral("exports")); // Try "module.exports". If this declaration exists, it contains the // module's exports exports = getDeclaration(idModule, topContext.data()); if (exports && exports->internalContext()) { exports = getDeclaration(idExports, exports->internalContext(), false); } // Try "exports", that always exist, has a structure type, and contains // the exported symbols if (!exports) { exports = getDeclaration(idExports, topContext.data()); } } return exports; } DeclarationPointer NodeJS::moduleMember(const QString& moduleName, const QString& memberName, const IndexedString& url) { DeclarationPointer module = moduleExports(moduleName, url); DeclarationPointer member; if (module) { member = QmlJS::getDeclaration( QualifiedIdentifier(memberName), QmlJS::getInternalContext(module), false ); } return member; } Path::List NodeJS::moduleDirectories(const QString& url) { Path::List paths; // QML/JS ships several modules that exist only in binary form in Node.js QStringList dirs = QStandardPaths::locateAll( QStandardPaths::GenericDataLocation, QStringLiteral("kdevqmljssupport/nodejsmodules"), QStandardPaths::LocateDirectory ); for (auto dir : dirs) { paths.append(Path(dir)); } // url/../node_modules, then url/../../node_modules, etc Path path(url); path.addPath(QStringLiteral("..")); - while (path.segments().size() > 1) { + const int maxPathSize = path.isLocalFile() ? 1 : 2; + while (path.segments().size() > maxPathSize) { paths.append(path.cd(QStringLiteral("node_modules"))); path.addPath(QStringLiteral("..")); } return paths; } QString NodeJS::moduleFileName(const QString& moduleName, const QString& url) { QMutexLocker lock(&m_mutex); auto pair = qMakePair(moduleName, url); if (m_cachedModuleFileNames.contains(pair)) { return m_cachedModuleFileNames.value(pair); } QString& fileName = m_cachedModuleFileNames[pair]; // Absolue and relative URLs if (moduleName.startsWith(QLatin1Char('/')) || moduleName.startsWith(QLatin1Char('.'))) { // NOTE: This is not portable to Windows, but the Node.js documentation // only talks about module names that start with /, ./ and ../ . fileName = fileOrDirectoryPath(Path(url).cd(QStringLiteral("..")).cd(moduleName).toLocalFile()); return fileName; } // Try all the paths that might contain modules for (auto path : moduleDirectories(url)) { fileName = fileOrDirectoryPath(path.cd(moduleName).toLocalFile()); if (!fileName.isNull()) { break; } } return fileName; } QString NodeJS::fileOrDirectoryPath(const QString& baseName) { if (QFile::exists(baseName)) { return baseName; } else if (QFile::exists(baseName + QLatin1String(".js"))) { return baseName + QLatin1String(".js"); } else if (QFile::exists(baseName + QLatin1String("/index.js"))) { // TODO: package.json files currently not supported return baseName + QLatin1String("/index.js"); } return QString(); } } diff --git a/utils/okteta/kdevokteta.json b/utils/okteta/kdevokteta.json index 9443c1ccd7..b597957ab2 100644 --- a/utils/okteta/kdevokteta.json +++ b/utils/okteta/kdevokteta.json @@ -1,55 +1,54 @@ { "KPlugin": { "Authors": [ { "Email": "kossebau@kde.org", "Name": "Friedrich W. H. Kossebau", "Name[x-test]": "xxFriedrich W. H. Kossebauxx" } ], "Category": "Utilities", "Description": "Enables viewing and editing of the raw data of files (Okteta-based)", "Description[ca@valencia]": "Permet la visualització i edició de les dades crues dels fitxers (basat en l'Okteta)", "Description[ca]": "Permet la visualització i edició de les dades crues dels fitxers (basat en l'Okteta)", "Description[de]": "Ermöglicht das Betrachten und Bearbeiten der Rohdaten von Dateien (basiert auf Okteta)", "Description[es]": "Activa la visualización y la edición de datos de archivos en bruto (basado en Okteta)", "Description[fr]": "Permet de visualiser et éditer les données brutes de fichiers (basé sur Okteta)", "Description[it]": "Abilita la visualizzazione e la modifica dei dati grezzi dei file (basato su Okteta)", "Description[nl]": "Schakelt het bekijken en bewerken van de ruwe gegevens van bestanden in (gebaseerd op Okteta)", "Description[pl]": "Umożliwia oglądanie i edytowanie nieprzetworzonych danych pliku (w oparciu o Oktetę)", "Description[pt]": "Permite a visualização e edição dos dados em bruto dos ficheiros (baseado no Okteta)", "Description[sk]": "Povolí prezeranie a editáciu raw dát súborov (založené na Okteta)", "Description[sl]": "Omogoča pregledovanje in urejanje surovih podatkov datotek (temelji na Okteti)", "Description[sv]": "Möjliggör granskning och redigering av rådata i filer (baserad på Okteta)", "Description[tr]": "Dosyaların ham verisini okuma ve düzenlemeyi sağlar (Oktet-tabanlı)", "Description[uk]": "Уможливлює перегляд і редагування необроблених даних у файлах (на основі Okteta)", "Description[x-test]": "xxEnables viewing and editing of the raw data of files (Okteta-based)xx", "Icon": "okteta", "Id": "kdevokteta", "License": "GPL", "Name": "Hex Editor", "Name[ca@valencia]": "Editor hexadecimal", "Name[ca]": "Editor hexadecimal", "Name[cs]": "Hexa editor", "Name[de]": "Hex-Editor", "Name[es]": "Editor hexadecimal", "Name[fr]": "Éditeur hexadécimal", "Name[it]": "Editor esadecimale", "Name[nl]": "Hexbewerker", "Name[pl]": "Edytor szesnastkowy", "Name[pt]": "Editor Hexadecimal", "Name[sk]": "Hex editor", "Name[sl]": "Šestnajstiški urejevalnik", "Name[sv]": "Hexadecimaleditor", "Name[tr]": "Hex Düzenleyici", "Name[uk]": "Шістнадцятковий редактор", "Name[x-test]": "xxHex Editorxx", "ServiceTypes": [ "KDevelop/Plugin" ], "Version": "0.1.0" }, "X-KDevelop-Category": "Global", - "X-KDevelop-Mode": "GUI", - "X-KDevelop-Version": "@KDEV_PLUGIN_VERSION@" + "X-KDevelop-Mode": "GUI" }