dockerfile-language-service
Version:
A language service for Dockerfiles to enable the creation of feature-rich Dockerfile editors.
225 lines (224 loc) • 11.2 kB
JavaScript
(function (factory) {
if (typeof module === "object" && typeof module.exports === "object") {
var v = factory(require, exports);
if (v !== undefined) module.exports = v;
}
else if (typeof define === "function" && define.amd) {
define(["require", "exports", "vscode-languageserver-types", "dockerfile-ast", "./docker"], factory);
}
})(function (require, exports) {
/* --------------------------------------------------------------------------------------------
* Copyright (c) Remy Suen. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
exports.DockerHover = void 0;
var vscode_languageserver_types_1 = require("vscode-languageserver-types");
var dockerfile_ast_1 = require("dockerfile-ast");
var docker_1 = require("./docker");
var DockerHover = /** @class */ (function () {
function DockerHover(markdown, plainText) {
this.markdown = markdown;
this.plainText = plainText;
}
DockerHover.prototype.onHover = function (content, position, markupKind) {
var dockerfile = dockerfile_ast_1.DockerfileParser.parse(content);
var image = dockerfile.getContainingImage(position);
if (!image) {
// position is invalid, not inside the Dockerfile
return null;
}
var key = this.computeHoverKey(dockerfile, position);
if (key) {
// if it's not a raw value, apply markup if necessary
if (markupKind && markupKind.length > 0) {
switch (markupKind[0]) {
case vscode_languageserver_types_1.MarkupKind.Markdown:
var markdownDocumentation = this.markdown.getMarkdown(key);
if (markdownDocumentation) {
return {
contents: {
kind: vscode_languageserver_types_1.MarkupKind.Markdown,
value: markdownDocumentation.contents
}
};
}
return null;
case vscode_languageserver_types_1.MarkupKind.PlainText:
var plainTextDocumentation = this.plainText.getDocumentation(key);
if (plainTextDocumentation) {
return {
contents: {
kind: vscode_languageserver_types_1.MarkupKind.PlainText,
value: plainTextDocumentation
}
};
}
}
return null;
}
var hover = this.markdown.getMarkdown(key);
return hover === undefined ? null : hover;
}
for (var _i = 0, _a = image.getInstructions(); _i < _a.length; _i++) {
var instruction = _a[_i];
if (instruction instanceof dockerfile_ast_1.Arg) {
// hovering over an argument defined by ARG
var property = instruction.getProperty();
if (property && docker_1.Util.isInsideRange(position, property.getNameRange()) && property.getValue() !== null) {
return { contents: property.getValue() };
}
}
if (instruction instanceof dockerfile_ast_1.Env) {
// hovering over an argument defined by ENV
for (var _b = 0, _c = instruction.getProperties(); _b < _c.length; _b++) {
var property = _c[_b];
if (docker_1.Util.isInsideRange(position, property.getNameRange()) && property.getValue() !== null) {
return {
contents: property.getValue()
};
}
}
}
}
for (var _d = 0, _e = image.getInstructions(); _d < _e.length; _d++) {
var instruction = _e[_d];
for (var _f = 0, _g = instruction.getVariables(); _f < _g.length; _f++) {
var variable = _g[_f];
// are we hovering over a variable
if (docker_1.Util.isInsideRange(position, variable.getNameRange())) {
var resolved = dockerfile.resolveVariable(variable.getName(), variable.getNameRange().start.line);
if (resolved || resolved === "") {
return { contents: resolved };
}
else if (resolved === null) {
return null;
}
}
}
}
return null;
};
/**
* Analyzes the Dockerfile at the given position to determine if the user
* is hovering over a keyword, a flag, or a directive.
*
* @param dockerfile the Dockerfile to check
* @param position the place that the user is hovering over
* @return the string key value for the keyword, flag, or directive that's
* being hovered over, or null if the user isn't hovering over
* such a word
*/
DockerHover.prototype.computeHoverKey = function (dockerfile, position) {
for (var _i = 0, _a = dockerfile.getDirectives(); _i < _a.length; _i++) {
var directive = _a[_i];
var range = directive.getNameRange();
switch (directive.getDirective()) {
case dockerfile_ast_1.Directive.escape:
if (docker_1.Util.isInsideRange(position, range)) {
return dockerfile_ast_1.Directive.escape;
}
break;
case dockerfile_ast_1.Directive.syntax:
if (docker_1.Util.isInsideRange(position, range)) {
return dockerfile_ast_1.Directive.syntax;
}
break;
}
}
var image = dockerfile.getContainingImage(position);
for (var _b = 0, _c = image.getInstructions(); _b < _c.length; _b++) {
var instruction = _c[_b];
var instructionRange = instruction.getInstructionRange();
if (docker_1.Util.isInsideRange(position, instructionRange)) {
return instruction.getKeyword();
}
if (instruction instanceof dockerfile_ast_1.Onbuild) {
// hovering over a trigger instruction of an ONBUILD
var range = instruction.getTriggerRange();
if (docker_1.Util.isInsideRange(position, range)) {
return instruction.getTrigger();
}
}
var hover = this.getFlagsHover(position, instruction);
if (hover !== null) {
return hover;
}
}
return null;
};
DockerHover.prototype.getFlagsHover = function (position, instruction) {
switch (instruction.getKeyword()) {
case "ADD":
var addFlags = instruction.getFlags();
for (var _i = 0, addFlags_1 = addFlags; _i < addFlags_1.length; _i++) {
var flag = addFlags_1[_i];
if (docker_1.Util.isInsideRange(position, flag.getNameRange())) {
switch (flag.getName()) {
case "chown":
return "ADD_FlagChown";
}
}
}
break;
case "COPY":
var copyFlags = instruction.getFlags();
for (var _a = 0, copyFlags_1 = copyFlags; _a < copyFlags_1.length; _a++) {
var flag = copyFlags_1[_a];
if (docker_1.Util.isInsideRange(position, flag.getNameRange())) {
switch (flag.getName()) {
case "chown":
return "COPY_FlagChown";
case "from":
return "COPY_FlagFrom";
}
}
}
break;
case "FROM":
var fromFlags = instruction.getFlags();
for (var _b = 0, fromFlags_1 = fromFlags; _b < fromFlags_1.length; _b++) {
var flag = fromFlags_1[_b];
if (docker_1.Util.isInsideRange(position, flag.getNameRange())) {
if (flag.getName() === "platform") {
return "FROM_FlagPlatform";
}
return null;
}
}
break;
case "HEALTHCHECK":
var flags = instruction.getFlags();
for (var _c = 0, flags_1 = flags; _c < flags_1.length; _c++) {
var flag = flags_1[_c];
if (docker_1.Util.isInsideRange(position, flag.getNameRange())) {
switch (flag.getName()) {
case "interval":
return "HEALTHCHECK_FlagInterval";
case "retries":
return "HEALTHCHECK_FlagRetries";
case "start-interval":
return "HEALTHCHECK_FlagStartInterval";
case "start-period":
return "HEALTHCHECK_FlagStartPeriod";
case "timeout":
return "HEALTHCHECK_FlagTimeout";
}
return null;
}
}
break;
case "ONBUILD":
var trigger = instruction.getTriggerInstruction();
if (trigger !== null) {
return this.getFlagsHover(position, trigger);
}
break;
}
return null;
};
return DockerHover;
}());
exports.DockerHover = DockerHover;
});