🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
Sign inDemoInstall
Socket

dockerfile-language-server-nodejs

Package Overview
Dependencies
Maintainers
1
Versions
47
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

dockerfile-language-server-nodejs - npm Package Compare versions

Comparing version

to
0.0.7

lib/dockerRegistryClient.js

37

CHANGELOG.md

@@ -6,2 +6,36 @@ # Changelog

## [0.0.7] - 2017-09-09
### Added
- textDocument/completion
- COPY's --from build stage flag ([#148](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/148))
- add '-' as a trigger character to suggest instruction flags ([#155](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/155))
- suggest image tags in FROM instructions ([#154](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/154))
- set source image as suggested build stage's documentation text ([#159](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/159))
- suggest numeric build stage index if source image is unnamed ([#160](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/160))
- textDocument/hover
- COPY's --from build stage flag ([#150](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/150))
- textDocument/publishDiagnostics
- warn if ENV or LABEL is missing closing quote ([#143](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/143))
- warn if FROM's build stage name is invalid ([#132](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/132))
- warn if an invalid unit of time is used in a duration flag ([#152](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/152))
- warn if COPY does not have two arguments ([#157](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/157))
- textDocument/signatureHelp
- escape parser directive ([#147](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/147))
- instruction flags ([#147](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/147))
- COPY's --from
- HEALTHCHECK CMD flags
- instructions ([#162](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/162))
### Fixed
- correct handling of escaped quotes in ENV variables ([#144](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/144))
- include escape character in value of single quoted ENV variables ([#146](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/146))
- ignore whitespace that precedes an escaped newline in ENV variables ([#147](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/147))
- fix handling of escape characters in SHELL's JSON strings ([#151](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/151))
- do not suggest duplicated build stage names as completion items ([#156](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/156))
- only suggest build stages that come after the current COPY line ([#158](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/158))
- restrict operations on ARG and ENV variables to a build stage ([#163](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/163))
- make FROM variables only interact with the initial set of ARG instructions ([#153](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/153))
- skip validation of nested comments in escaped newlines of ENV and LABEL instructions ([#167](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/167))
- prevent hovers from rendering nested comments for ARG and ENV instructions ([#168](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/168))
## [0.0.6] - 2017-08-12

@@ -161,3 +195,4 @@ ### Added

[Unreleased]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.6...HEAD
[Unreleased]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.7...HEAD
[0.0.7]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.6...v0.0.7
[0.0.6]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.5...v0.0.6

@@ -164,0 +199,0 @@ [0.0.5]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.4...v0.0.5

17

lib/docker.js

@@ -91,8 +91,17 @@ /* --------------------------------------------------------------------------------------------

static rangeEquals(range, range2) {
return range.start.line === range2.start.line
&& range.start.character === range2.start.character
&& range.end.line === range2.end.line
&& range.end.character === range2.end.character;
return Util.positionEquals(range.start, range2.start) && Util.positionEquals(range.end, range2.end);
}
static positionEquals(position, position2) {
return position.line == position2.line && position.character === position2.character;
}
static positionBefore(origin, other) {
if (origin.line < other.line) {
return true;
}
else if (origin.line > other.line) {
return false;
}
return origin.character < other.character;
}
}
exports.Util = Util;

@@ -6,2 +6,10 @@ /* --------------------------------------------------------------------------------------------

'use strict';
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });

@@ -12,5 +20,13 @@ const vscode_languageserver_1 = require("vscode-languageserver");

class DockerAssist {
constructor(document, snippetSupport) {
/**
* Creates a content assist processor for suggesting completion items related to a Dockerfile.
*
* @param document the text document to provide suggestions for
* @param snippetSupport true if snippets are supported by the client, false otherwise
* @param dockerRegistryClient the client for communicating with a Docker registry
*/
constructor(document, snippetSupport, dockerRegistryClient) {
this.document = document;
this.snippetSupport = snippetSupport;
this.dockerRegistryClient = dockerRegistryClient;
}

@@ -120,3 +136,5 @@ computeProposals(document, position) {

case "COPY":
return this.createBuildStageProposals(dockerfile, instruction, position, offset);
return this.createCopyProposals(dockerfile, instruction, position, offset, prefix);
case "FROM":
return this.createFromProposals(instruction, position, prefix);
case "HEALTHCHECK":

@@ -137,8 +155,13 @@ let subcommand = instruction.getSubcommand();

let trigger = instruction.getTriggerInstruction();
if (trigger !== null && trigger.getKeyword() === "HEALTHCHECK") {
let subcommand = trigger.getSubcommand();
if (subcommand && subcommand.isBefore(position)) {
return [];
if (trigger !== null) {
switch (trigger.getKeyword()) {
case "COPY":
return this.createCopyProposals(dockerfile, trigger, position, offset, prefix);
case "HEALTHCHECK":
let subcommand = trigger.getSubcommand();
if (subcommand && subcommand.isBefore(position)) {
return [];
}
return this.createHealthcheckProposals(dockerfile, position, offset, prefix);
}
return this.createHealthcheckProposals(dockerfile, position, offset, prefix);
}

@@ -208,22 +231,82 @@ }

}
createBuildStageProposals(dockerfile, copy, position, offset) {
createCopyProposals(dockerfile, copy, position, offset, prefix) {
let range = copy.getFromValueRange();
// is the user in the --from= area
if (range && docker_1.Util.isInsideRange(position, copy.getFromValueRange())) {
const names = {};
const items = [];
let stageIndex = 0;
// determines if the last build stage was named or not
let lastNumber = false;
// get the prefix
let prefix = this.document.getText().substring(this.document.offsetAt(range.start), offset).toLowerCase();
let items = [];
let stagePrefix = this.document.getText().substring(this.document.offsetAt(range.start), offset).toLowerCase();
for (let from of dockerfile.getFROMs()) {
let stage = from.getBuildStage();
if (stage && stage.toLowerCase().indexOf(prefix) === 0) {
items.push(this.createSourceImageCompletionItem(stage, prefix.length, offset));
if (copy.isAfter(from)) {
const image = from.getImage();
let stage = from.getBuildStage();
if (stage) {
const lowercase = stage.toLowerCase();
if (lowercase.indexOf(stagePrefix) === 0 && !names[lowercase]) {
names[lowercase] = true;
items.push(this.createSourceImageCompletionItem(stage, image, stageIndex, stagePrefix.length, offset));
}
lastNumber = false;
}
else if (!names[stageIndex]) {
names[stageIndex] = true;
items.push(this.createSourceImageCompletionItem(stageIndex.toString(), image, stageIndex, stagePrefix.length, offset));
lastNumber = true;
}
stageIndex++;
}
else {
break;
}
}
items.sort((item, item2) => {
return item.label.localeCompare(item2.label);
});
// last build stage was not named, don't suggest it as it is recursive
if (lastNumber && items.length > 0) {
items.pop();
}
return items;
}
const flags = copy.getFlags();
let copyArgs = copy.getArguments();
if (copyArgs.length === 0 && copy.getFlags().length === 0) {
return [this.createCOPY_FlagFrom(0, offset)];
}
else if ((copyArgs.length > 0 && docker_1.Util.isInsideRange(position, copyArgs[0].getRange()) && "--from=".indexOf(prefix) === 0)
|| (flags.length > 0 && "--from=".indexOf(flags[0].toString()) === 0)) {
return [this.createCOPY_FlagFrom(prefix.length, offset)];
}
return [];
}
createFromProposals(from, position, prefix) {
// checks if the cursor is in the image's tag area
if (docker_1.Util.isInsideRange(position, from.getImageTagRange())) {
const index = prefix.indexOf(':');
const lastIndex = prefix.indexOf(':');
if (index === lastIndex) {
prefix = prefix.substring(index + 1);
}
else {
prefix = prefix.substring(index + 1, lastIndex);
}
const client = this.dockerRegistryClient;
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
const items = [];
const tags = yield client.getTags(from.getImageName());
for (const tag of tags) {
if (tag.indexOf(prefix) === 0) {
items.push({
label: tag,
kind: vscode_languageserver_1.CompletionItemKind.Property,
insertTextFormat: vscode_languageserver_1.InsertTextFormat.PlainText,
});
}
}
resolve(items);
}));
}
return [];
}
createHealthcheckProposals(dockerfile, position, offset, prefix) {

@@ -382,2 +465,8 @@ let items = [];

}
createCOPY_FlagFrom(prefixLength, offset) {
if (this.snippetSupport) {
return this.createFlagCompletionItem("--from=stage", prefixLength, offset, "--from=${1:stage}", "COPY_FlagFrom");
}
return this.createFlagCompletionItem("--from=", prefixLength, offset, "--from=", "COPY_FlagFrom");
}
createHEALTHCHECK_FlagInterval(prefixLength, offset) {

@@ -435,3 +524,3 @@ if (this.snippetSupport) {

createWORKDIR(prefixLength, offset, markdown) {
return this.createKeywordCompletionItem("WORKDIR", "WORKDIR /path", prefixLength, offset, "WORKDIR ${1:/path}", markdown);
return this.createKeywordCompletionItem("WORKDIR", "WORKDIR /the/workdir/path", prefixLength, offset, "WORKDIR ${1:/the/workdir/path}", markdown);
}

@@ -477,8 +566,10 @@ createEscape(prefixLength, offset, markdown) {

}
createSourceImageCompletionItem(label, prefixLength, offset) {
createSourceImageCompletionItem(label, documentation, buildIndex, prefixLength, offset) {
return {
textEdit: this.createTextEdit(prefixLength, offset, label),
label: label,
documentation: documentation,
kind: vscode_languageserver_1.CompletionItemKind.Reference,
insertTextFormat: vscode_languageserver_1.InsertTextFormat.PlainText,
sortText: buildIndex.toString()
};

@@ -485,0 +576,0 @@ }

@@ -31,5 +31,5 @@ /* --------------------------------------------------------------------------------------------

}
static computeVariableDefinition(dockerfile, position) {
static computeVariableDefinition(image, position) {
let variableName = null;
for (let arg of dockerfile.getARGs()) {
for (let arg of image.getARGs()) {
let property = arg.getProperty();

@@ -46,3 +46,3 @@ // might be an ARG with no arguments

if (variableName === null) {
variableCheck: for (let env of dockerfile.getENVs()) {
variableCheck: for (let env of image.getENVs()) {
let properties = env.getProperties();

@@ -59,3 +59,3 @@ for (let property of properties) {

if (variableName === null) {
variableCheck: for (let instruction of dockerfile.getInstructions()) {
variableCheck: for (let instruction of image.getInstructions()) {
for (let variable of instruction.getVariables()) {

@@ -69,3 +69,3 @@ if (docker_1.Util.isInsideRange(position, variable.getNameRange())) {

}
for (let instruction of dockerfile.getInstructions()) {
for (let instruction of image.getInstructions()) {
if (instruction instanceof arg_1.Arg) {

@@ -89,4 +89,21 @@ let property = instruction.getProperty();

}
static findDefinition(dockerfile, position) {
for (const from of dockerfile.getFROMs()) {
for (const variable of from.getVariables()) {
if (docker_1.Util.isInsideRange(position, variable.getNameRange())) {
for (const arg of dockerfile.getInitialARGs()) {
const property = arg.getProperty();
if (property && property.getName() === variable.getName()) {
return property;
}
}
return null;
}
}
}
let image = dockerfile.getContainingImage(position);
return DockerDefinition.computeVariableDefinition(image, position);
}
computeVariableDefinition(uri, dockerfile, position) {
let property = DockerDefinition.computeVariableDefinition(dockerfile, position);
const property = DockerDefinition.findDefinition(dockerfile, position);
return property ? vscode_languageserver_1.Location.create(uri, property.getNameRange()) : null;

@@ -93,0 +110,0 @@ }

@@ -9,2 +9,3 @@ /* --------------------------------------------------------------------------------------------

const dockerfileParser_1 = require("./parser/dockerfileParser");
const from_1 = require("./parser/instructions/from");
const dockerDefinition_1 = require("./dockerDefinition");

@@ -18,2 +19,3 @@ const docker_1 = require("./docker");

let location = provider.computeDefinition(document, position);
let image = location === null ? dockerfile.getContainingImage(position) : dockerfile.getContainingImage(location.range.start);
let highlights = [];

@@ -34,10 +36,27 @@ if (location === null) {

}
for (let instruction of dockerfile.getInstructions()) {
for (const from of dockerfile.getFROMs()) {
for (const variable of from.getVariables()) {
if (docker_1.Util.isInsideRange(position, variable.getNameRange())) {
const name = variable.getName();
for (const loopFrom of dockerfile.getFROMs()) {
for (const fromVariable of loopFrom.getVariables()) {
if (fromVariable.getName() === name) {
highlights.push(vscode_languageserver_1.DocumentHighlight.create(fromVariable.getNameRange(), vscode_languageserver_1.DocumentHighlightKind.Read));
}
}
}
return highlights;
}
}
}
for (let instruction of image.getInstructions()) {
for (let variable of instruction.getVariables()) {
if (docker_1.Util.isInsideRange(position, variable.getNameRange())) {
let name = variable.getName();
for (let instruction of dockerfile.getInstructions()) {
for (let variable of instruction.getVariables()) {
if (variable.getName() === name) {
highlights.push(vscode_languageserver_1.DocumentHighlight.create(variable.getNameRange(), vscode_languageserver_1.DocumentHighlightKind.Read));
for (let instruction of image.getInstructions()) {
if (!(instruction instanceof from_1.From)) {
for (let variable of instruction.getVariables()) {
if (variable.getName() === name) {
highlights.push(vscode_languageserver_1.DocumentHighlight.create(variable.getNameRange(), vscode_languageserver_1.DocumentHighlightKind.Read));
}
}

@@ -66,3 +85,3 @@ }

}
for (let arg of dockerfile.getARGs()) {
for (let arg of image.getARGs()) {
let property = arg.getProperty();

@@ -74,3 +93,3 @@ // property may be null if it's an ARG with no arguments

}
for (let env of dockerfile.getENVs()) {
for (let env of image.getENVs()) {
for (let property of env.getProperties()) {

@@ -82,9 +101,24 @@ if (property.getName() === definition) {

}
for (let instruction of dockerfile.getInstructions()) {
for (let variable of instruction.getVariables()) {
if (variable.getName() === definition) {
highlights.push(vscode_languageserver_1.DocumentHighlight.create(variable.getNameRange(), vscode_languageserver_1.DocumentHighlightKind.Read));
for (let instruction of image.getInstructions()) {
// only highlight variables in non-FROM instructions
if (!(instruction instanceof from_1.From)) {
for (const variable of instruction.getVariables()) {
if (variable.getName() === definition) {
highlights.push(vscode_languageserver_1.DocumentHighlight.create(variable.getNameRange(), vscode_languageserver_1.DocumentHighlightKind.Read));
}
}
}
}
for (const arg of dockerfile.getInitialARGs()) {
const property = arg.getProperty();
if (property && docker_1.Util.rangeEquals(property.getNameRange(), location.range)) {
for (const from of dockerfile.getFROMs()) {
for (const variable of from.getVariables()) {
if (variable.getName() === definition) {
highlights.push(vscode_languageserver_1.DocumentHighlight.create(variable.getNameRange(), vscode_languageserver_1.DocumentHighlightKind.Read));
}
}
}
}
}
}

@@ -91,0 +125,0 @@ return highlights;

@@ -21,2 +21,3 @@ /* --------------------------------------------------------------------------------------------

let directive = dockerfile.getDirective();
let image = dockerfile.getContainingImage(textDocumentPosition.position);
if (textDocumentPosition.position.line === 0 && directive !== null && directive.getDirective() === docker_1.DIRECTIVE_ESCAPE) {

@@ -28,7 +29,7 @@ let range = directive.getNameRange();

}
for (let instruction of dockerfile.getInstructions()) {
for (let instruction of image.getInstructions()) {
for (let variable of instruction.getVariables()) {
// are we hovering over a variable
if (docker_1.Util.isInsideRange(textDocumentPosition.position, variable.getNameRange())) {
let instructions = dockerfile.getInstructions();
let instructions = image.getInstructions();
for (let i = instructions.length - 1; i >= 0; i--) {

@@ -48,3 +49,3 @@ // only look for variables defined before the current instruction

}
for (let instruction of dockerfile.getInstructions()) {
for (let instruction of image.getInstructions()) {
let instructionRange = instruction.getInstructionRange();

@@ -80,45 +81,8 @@ if (docker_1.Util.isInsideRange(textDocumentPosition.position, instructionRange)) {

}
switch (instruction.getKeyword()) {
case "HEALTHCHECK":
let flags = instruction.getFlags();
for (let flag of flags) {
if (docker_1.Util.isInsideRange(textDocumentPosition.position, flag.getNameRange())) {
switch (flag.getName()) {
case "interval":
return this.markdown.getMarkdown("HEALTHCHECK_FlagInterval");
case "retries":
return this.markdown.getMarkdown("HEALTHCHECK_FlagRetries");
case "start-period":
return this.markdown.getMarkdown("HEALTHCHECK_FlagStartPeriod");
case "timeout":
return this.markdown.getMarkdown("HEALTHCHECK_FlagTimeout");
}
return null;
}
}
break;
case "ONBUILD":
let onbuild = instruction;
if (onbuild.getTrigger() === "HEALTHCHECK") {
let flags = onbuild.getTriggerInstruction().getFlags();
for (let flag of flags) {
if (docker_1.Util.isInsideRange(textDocumentPosition.position, flag.getNameRange())) {
switch (flag.getName()) {
case "interval":
return this.markdown.getMarkdown("HEALTHCHECK_FlagInterval");
case "retries":
return this.markdown.getMarkdown("HEALTHCHECK_FlagRetries");
case "start-period":
return this.markdown.getMarkdown("HEALTHCHECK_FlagStartPeriod");
case "timeout":
return this.markdown.getMarkdown("HEALTHCHECK_FlagTimeout");
}
return null;
}
}
}
break;
let hover = this.getFlagsHover(textDocumentPosition.position, instruction);
if (hover !== undefined) {
return hover;
}
}
let property = dockerDefinition_1.DockerDefinition.computeVariableDefinition(dockerfile, textDocumentPosition.position);
let property = dockerDefinition_1.DockerDefinition.findDefinition(dockerfile, textDocumentPosition.position);
if (property && property.getValue() !== null) {

@@ -129,3 +93,38 @@ return { contents: property.getValue() };

}
getFlagsHover(position, instruction) {
switch (instruction.getKeyword()) {
case "COPY":
let copyFlags = instruction.getFlags();
if (copyFlags.length > 0 && docker_1.Util.isInsideRange(position, copyFlags[0].getNameRange()) && copyFlags[0].getName() === "from") {
return this.markdown.getMarkdown("COPY_FlagFrom");
}
break;
case "HEALTHCHECK":
let flags = instruction.getFlags();
for (let flag of flags) {
if (docker_1.Util.isInsideRange(position, flag.getNameRange())) {
switch (flag.getName()) {
case "interval":
return this.markdown.getMarkdown("HEALTHCHECK_FlagInterval");
case "retries":
return this.markdown.getMarkdown("HEALTHCHECK_FlagRetries");
case "start-period":
return this.markdown.getMarkdown("HEALTHCHECK_FlagStartPeriod");
case "timeout":
return this.markdown.getMarkdown("HEALTHCHECK_FlagTimeout");
}
return null;
}
}
break;
case "ONBUILD":
let trigger = instruction.getTriggerInstruction();
if (trigger !== null) {
return this.getFlagsHover(position, trigger);
}
break;
}
return undefined;
}
}
exports.DockerHover = DockerHover;

@@ -30,5 +30,6 @@ /* --------------------------------------------------------------------------------------------

"hoverOnlineDocumentationFooter": "\n\n[Online documentation](${0})",
"hoverCopyFlagFrom": "The previous build stage to use as the source location instead of the build's context.\n\nSince Docker 17.05.0-ce.",
"hoverHealthcheckFlagInterval": "The seconds to wait for the health check to run after the container has started, and then again the number of seconds to wait before running again after the previous check has completed.",
"hoverHealthcheckFlagRetries": "The number of consecutive failures of this health check before the container is considered to be `unhealthy`.",
"hoverHealthcheckFlagStartPeriod": "The number of seconds to wait for the container to startup. Failures during this grace period will not count towards the maximum number of retries. However, should a health check succeed during this period then any subsequent failures will count towards the maximum number of retries.",
"hoverHealthcheckFlagStartPeriod": "The number of seconds to wait for the container to startup. Failures during this grace period will not count towards the maximum number of retries. However, should a health check succeed during this period then any subsequent failures will count towards the maximum number of retries.\n\nSince Docker 17.05.0-ce.",
"hoverHealthcheckFlagTimeout": "The number of seconds to wait for the check to complete before considering it to have failed.",

@@ -72,2 +73,5 @@ "proposalArgNameOnly": "Define a variable that users can set at build-time when using `docker build`.\n\n",

},
COPY_FlagFrom: {
contents: this.dockerMessages["hoverCopyFlagFrom"]
},
ENTRYPOINT: {

@@ -74,0 +78,0 @@ contents: this.dockerMessages["hoverEntrypoint"] +

@@ -28,7 +28,73 @@ /* --------------------------------------------------------------------------------------------

"hoverWorkdir": "Set the working directory for any subsequent ADD, COPY, CMD, ENTRYPOINT, or RUN` instructions that follow it in the `Dockerfile`.\n\n",
"hoverCopyFlagFrom": "The previous build stage to use as the source location instead of the build's context.\n\nSince Docker 17.05.0-ce.",
"hoverHealthcheckFlagInterval": "The seconds to wait for the health check to run after the container has started, and then again the number of seconds to wait before running again after the previous check has completed.",
"hoverHealthcheckFlagRetries": "The number of consecutive failures of this health check before the container is considered to be `unhealthy`.",
"hoverHealthcheckFlagStartPeriod": "The number of seconds to wait for the container to startup. Failures during this grace period will not count towards the maximum number of retries. However, should a health check succeed during this period then any subsequent failures will count towards the maximum number of retries.",
"hoverHealthcheckFlagStartPeriod": "The number of seconds to wait for the container to startup. Failures during this grace period will not count towards the maximum number of retries. However, should a health check succeed during this period then any subsequent failures will count towards the maximum number of retries.\n\nSince Docker 17.05.0-ce.",
"hoverHealthcheckFlagTimeout": "The number of seconds to wait for the check to complete before considering it to have failed.",
"hoverEscape": "Sets the character to use to escape characters and newlines in this Dockerfile. If unspecified, the default escape character is `\\`.\n\n",
"signatureEscape": "Sets this Dockerfile's escape character. If unspecified, the default escape character is `\\`.",
"signatureEscape_Param": "The character to use to escape characters and newlines in this Dockerfile.",
"signatureAdd_Signature0": "Copy new files, directories or remote URLs to the image's filesystem.",
"signatureAdd_Signature0_Param0": "The resource to copy or unpack if it is a local tar archive in a recognized compression format.",
"signatureAdd_Signature0_Param2": "The name of the destination file or folder.",
"signatureArg_Signature0": "Define a variable that users can pass a value to at build-time with `docker build`.",
"signatureArg_Signature0_Param": "The name of the variable.",
"signatureArg_Signature1": "Define a variable with an optional default value that users can override at build-time with `docker build`.",
"signatureArg_Signature1_Param1": "The default value of the variable.",
"signatureCmd_Signature0": "Set the default executable and parameters for this executing container.",
"signatureCmd_Signature0_Param0": "The default executable for this executing container.",
"signatureCmd_Signature0_Param1": "A parameter to the default executable.",
"signatureCmd_Signature1": "Set the default parameters for this executing container. An ENTRYPOINT instruction must also be specified.",
"signatureCmd_Signature1_Param0": "A parameter to the entrypoint executable.",
"signatureCopy_Signature0": "Copy new files and directories to the image's filesystem.",
"signatureCopy_Signature0_Param0": "Optional flags to configure this instruction.",
"signatureCopy_Signature0_Param1": "The resource to copy.",
"signatureCopyFlagFrom": "Set the build stage to use as the source location of this copy instruction instead of the build's context.",
"signatureCopyFlagFrom_Param": "The build stage or image name to use as the source. Also may be a numeric index.",
"signatureEntrypoint_Signature0": "Configure this container for running as an executable.",
"signatureEntrypoint_Signature0_Param1": "The container's main executable.",
"signatureEntrypoint_Signature0_Param2": "A parameter to the entrypoint executable.",
"signatureEnv_Signature0": "Set an environment variable to the specified value. The value will be in the environment of any descendent Dockerfiles",
"signatureEnv_Signature0_Param0": "The name of the environment variable.",
"signatureEnv_Signature0_Param1": "The value to set the environment variable to.",
"signatureExpose": "Define network ports for this container to listen on at runtime.",
"signatureExpose_Param0": "The port that this container should listen on.",
"signatureFrom_Signature0": "Set the base image to use for any subsequent instructions that follow.",
"signatureFrom_Signature0_Param": "The name of the base image to use.",
"signatureFrom_Signature1_Param1": "The tag of the base image to use.",
"signatureFrom_Signature2_Param1": "The digest of the base image to use.",
"signatureFrom_Signature3": "Set the base image to use for any subsequent instructions that follow and also give this build stage a name.",
"signatureFrom_Signature3_Param2": "The name of this build stage.",
"signatureFrom_Param2": "The name of this build stage.",
"signatureHealthcheck_Signature0": "Define how Docker should test the container to check that it is still working.",
"signatureHealthcheck_Signature1_Param2": "The parameters to the CMD instruction for the healthcheck.",
"signatureHealthcheck_Signature2": "Disable the inherited HEALTHCHECK instruction from the base image.",
"signatureLabel_Signature0": "Set metadata to an image.",
"signatureLabel_Signature0_Param0": "The name of the metadata.",
"signatureLabel_Signature0_Param1": "The value of the metadata.",
"signatureMaintainer": "Set the \"Author\" field of this image.",
"signatureMaintainer_Param": "The name of this image's maintainer.",
"signatureOnbuild": "Register a build instruction as a trigger to be executed when this image is used as a base image for another build.",
"signatureOnbuild_Param": "The build instruction to register as a trigger instruction.",
"signatureRun_Signature0": "Execute commands inside a shell.",
"signatureRun_Signature0_Param0": "The command to run.",
"signatureRun_Signature0_Param1": "A parameter to the command.",
"signatureRun_Signature1": "Execute commands without invoking a command shell.",
"signatureShell": "Override default shell used for the shell form of commands.",
"signatureShell_Param1": "The shell executable to use.",
"signatureShell_Param2": "The parameters to the shell executable.",
"signatureStopsignal": "Set the system call signal to use to send to the container to exit.",
"signatureStopsignal_Param": "The signal to send to the container to exit. This may be an valid unsigned number or a signal name in the SIGNAME format such as SIGKILL.",
"signatureUser_Signature0": "Set the user name to use for running any RUN, CMD, and ENTRYPOINT instructions that follow.",
"signatureUser_Signature0_Param": "The user name to use.",
"signatureUser_Signature1": "Set the user name and user group to use for running any RUN, CMD, and ENTRYPOINT instructions that follow.",
"signatureUser_Signature1_Param1": "The group name to use.",
"signatureUser_Signature2": "Set the UID to use for running any RUN, CMD, and ENTRYPOINT instructions that follow.",
"signatureUser_Signature2_Param": "The UID to use.",
"signatureUser_Signature3": "Set the UID and GID to use for running any RUN, CMD, and ENTRYPOINT instructions that follow.",
"signatureUser_Signature3_Param1": "The GID to use.",
"signatureVolume_Signature0": "Create mount points for holding externally mounted volumes from the native host or other containers.",
"signatureVolume_Signature0_Param0": "The name of the mount point.",
"signatureWorkdir": "Set the working directory for any ADD, COPY, CMD, ENTRYPOINT, or RUN instructions that follow.",
"signatureWorkdir_Param": "The absolute or relative path to use as the working directory. Will be created if it does not exist.",
"proposalArgNameOnly": "Define a variable that users can set at build-time when using `docker build`.\n\n",

@@ -55,2 +121,3 @@ "proposalArgDefaultValue": "Define a variable with the given default value that users can override at build-time when using `docker build`.\n\n",

"COPY hello.txt relative/to/workdir",
COPY_FlagFrom: this.dockerMessages["hoverCopyFlagFrom"],
ENTRYPOINT: this.dockerMessages["hoverEntrypoint"] +

@@ -101,3 +168,140 @@ "ENTRYPOINT [ \"/opt/app/run.sh\", \"--port\", \"8080\" ]",

escape: this.dockerMessages["hoverEscape"] +
"# escape=`"
"# escape=`",
signatureEscape: this.dockerMessages["signatureEscape"],
signatureEscape_Param: this.dockerMessages["signatureEscape_Param"],
signatureAdd_Signature0: this.dockerMessages["signatureAdd_Signature0"],
signatureAdd_Signature0_Param0: this.dockerMessages["signatureAdd_Signature0_Param0"],
signatureAdd_Signature0_Param1: this.dockerMessages["signatureAdd_Signature0_Param0"],
signatureAdd_Signature0_Param2: this.dockerMessages["signatureAdd_Signature0_Param2"],
signatureAdd_Signature1: this.dockerMessages["signatureAdd_Signature0"],
signatureAdd_Signature1_Param1: this.dockerMessages["signatureAdd_Signature0_Param0"],
signatureAdd_Signature1_Param2: this.dockerMessages["signatureAdd_Signature0_Param0"],
signatureAdd_Signature1_Param3: this.dockerMessages["signatureAdd_Signature0_Param2"],
signatureArg_Signature0: this.dockerMessages["signatureArg_Signature0"],
signatureArg_Signature0_Param: this.dockerMessages["signatureArg_Signature0_Param"],
signatureArg_Signature1: this.dockerMessages["signatureArg_Signature1"],
signatureArg_Signature1_Param0: this.dockerMessages["signatureArg_Signature0_Param"],
signatureArg_Signature1_Param1: this.dockerMessages["signatureArg_Signature1_Param1"],
signatureCmd_Signature0: this.dockerMessages["signatureCmd_Signature0"],
signatureCmd_Signature0_Param1: this.dockerMessages["signatureCmd_Signature0_Param0"],
signatureCmd_Signature0_Param2: this.dockerMessages["signatureCmd_Signature0_Param1"],
signatureCmd_Signature0_Param3: this.dockerMessages["signatureCmd_Signature0_Param1"],
signatureCmd_Signature1: this.dockerMessages["signatureCmd_Signature1"],
signatureCmd_Signature1_Param1: this.dockerMessages["signatureCmd_Signature1_Param0"],
signatureCmd_Signature1_Param2: this.dockerMessages["signatureCmd_Signature1_Param0"],
signatureCmd_Signature1_Param3: this.dockerMessages["signatureCmd_Signature1_Param0"],
signatureCmd_Signature2: this.dockerMessages["signatureCmd_Signature0"],
signatureCmd_Signature2_Param0: this.dockerMessages["signatureCmd_Signature0_Param0"],
signatureCmd_Signature2_Param1: this.dockerMessages["signatureCmd_Signature0_Param1"],
signatureCmd_Signature2_Param2: this.dockerMessages["signatureCmd_Signature0_Param1"],
signatureCopy_Signature0: this.dockerMessages["signatureCopy_Signature0"],
signatureCopy_Signature0_Param0: this.dockerMessages["signatureCopy_Signature0_Param0"],
signatureCopy_Signature0_Param1: this.dockerMessages["signatureCopy_Signature0_Param1"],
signatureCopy_Signature0_Param2: this.dockerMessages["signatureCopy_Signature0_Param1"],
signatureCopy_Signature0_Param3: this.dockerMessages["signatureAdd_Signature0_Param2"],
signatureCopy_Signature1: this.dockerMessages["signatureCopy_Signature0"],
signatureCopy_Signature1_Param0: this.dockerMessages["signatureCopy_Signature0_Param0"],
signatureCopy_Signature1_Param2: this.dockerMessages["signatureCopy_Signature0_Param1"],
signatureCopy_Signature1_Param3: this.dockerMessages["signatureCopy_Signature0_Param1"],
signatureCopy_Signature1_Param4: this.dockerMessages["signatureAdd_Signature0_Param2"],
signatureCopyFlagFrom: this.dockerMessages["signatureCopyFlagFrom"],
signatureCopyFlagFrom_Param: this.dockerMessages["signatureCopyFlagFrom_Param"],
signatureEntrypoint_Signature0: this.dockerMessages["signatureEntrypoint_Signature0"],
signatureEntrypoint_Signature0_Param1: this.dockerMessages["signatureEntrypoint_Signature0_Param1"],
signatureEntrypoint_Signature0_Param2: this.dockerMessages["signatureEntrypoint_Signature0_Param2"],
signatureEntrypoint_Signature0_Param3: this.dockerMessages["signatureEntrypoint_Signature0_Param2"],
signatureEntrypoint_Signature1: this.dockerMessages["signatureEntrypoint_Signature0"],
signatureEntrypoint_Signature1_Param0: this.dockerMessages["signatureEntrypoint_Signature0_Param1"],
signatureEntrypoint_Signature1_Param1: this.dockerMessages["signatureEntrypoint_Signature0_Param2"],
signatureEntrypoint_Signature1_Param2: this.dockerMessages["signatureEntrypoint_Signature0_Param2"],
signatureEnv_Signature0: this.dockerMessages["signatureEnv_Signature0"],
signatureEnv_Signature0_Param0: this.dockerMessages["signatureEnv_Signature0_Param0"],
signatureEnv_Signature0_Param1: this.dockerMessages["signatureEnv_Signature0_Param1"],
signatureEnv_Signature1: this.dockerMessages["signatureEnv_Signature0"],
signatureEnv_Signature1_Param0: this.dockerMessages["signatureEnv_Signature0_Param0"],
signatureEnv_Signature1_Param1: this.dockerMessages["signatureEnv_Signature0_Param1"],
signatureEnv_Signature2: this.dockerMessages["signatureEnv_Signature0"],
signatureEnv_Signature2_Param0: this.dockerMessages["signatureEnv_Signature0_Param0"],
signatureEnv_Signature2_Param1: this.dockerMessages["signatureEnv_Signature0_Param1"],
signatureEnv_Signature2_Param2: this.dockerMessages["signatureEnv_Signature0_Param0"],
signatureEnv_Signature2_Param3: this.dockerMessages["signatureEnv_Signature0_Param1"],
signatureExpose: this.dockerMessages["signatureExpose"],
signatureExpose_Param0: this.dockerMessages["signatureExpose_Param0"],
signatureExpose_Param1: this.dockerMessages["signatureExpose_Param0"],
signatureFrom_Signature0: this.dockerMessages["signatureFrom_Signature0"],
signatureFrom_Signature0_Param: this.dockerMessages["signatureFrom_Signature0_Param"],
signatureFrom_Signature1: this.dockerMessages["signatureFrom_Signature0"],
signatureFrom_Signature1_Param0: this.dockerMessages["signatureFrom_Signature0_Param"],
signatureFrom_Signature1_Param1: this.dockerMessages["signatureFrom_Signature1_Param1"],
signatureFrom_Signature2: this.dockerMessages["signatureFrom_Signature0"],
signatureFrom_Signature2_Param0: this.dockerMessages["signatureFrom_Signature0_Param"],
signatureFrom_Signature2_Param1: this.dockerMessages["signatureFrom_Signature2_Param1"],
signatureFrom_Signature3: this.dockerMessages["signatureFrom_Signature3"],
signatureFrom_Signature3_Param0: this.dockerMessages["signatureFrom_Signature0_Param"],
signatureFrom_Signature3_Param2: this.dockerMessages["signatureFrom_Signature3_Param2"],
signatureFrom_Signature4: this.dockerMessages["signatureFrom_Signature3"],
signatureFrom_Signature4_Param0: this.dockerMessages["signatureFrom_Signature0_Param"],
signatureFrom_Signature4_Param1: this.dockerMessages["signatureFrom_Signature1_Param1"],
signatureFrom_Signature4_Param3: this.dockerMessages["signatureFrom_Signature3_Param2"],
signatureFrom_Signature5: this.dockerMessages["signatureFrom_Signature3"],
signatureFrom_Signature5_Param0: this.dockerMessages["signatureFrom_Signature0_Param"],
signatureFrom_Signature5_Param1: this.dockerMessages["signatureFrom_Signature2_Param1"],
signatureFrom_Signature5_Param3: this.dockerMessages["signatureFrom_Signature3_Param2"],
signatureHealthcheck: this.dockerMessages["signatureHealthcheck_Signature0"],
signatureHealthcheck_Signature0: this.dockerMessages["signatureHealthcheck_Signature0"],
signatureHealthcheck_Signature1: this.dockerMessages["signatureHealthcheck_Signature0"],
signatureHealthcheck_Signature1_Param0: this.dockerMessages["signatureCopy_Signature0_Param0"],
signatureHealthcheck_Signature1_Param2: this.dockerMessages["signatureHealthcheck_Signature1_Param2"],
signatureHealthcheck_Signature2: this.dockerMessages["signatureHealthcheck_Signature0"],
signatureHealthcheckFlagInterval_Param: this.dockerMessages["hoverHealthcheckFlagInterval"],
signatureHealthcheckFlagRetries_Param: this.dockerMessages["hoverHealthcheckFlagRetries"],
signatureHealthcheckFlagStartPeriod_Param: this.dockerMessages["hoverHealthcheckFlagStartPeriod"],
signatureHealthcheckFlagTimeout_Param: this.dockerMessages["hoverHealthcheckFlagTimeout"],
signatureLabel_Signature0: this.dockerMessages["signatureLabel_Signature0"],
signatureLabel_Signature0_Param0: this.dockerMessages["signatureLabel_Signature0_Param0"],
signatureLabel_Signature0_Param1: this.dockerMessages["signatureLabel_Signature0_Param1"],
signatureLabel_Signature1: this.dockerMessages["signatureLabel_Signature0"],
signatureLabel_Signature1_Param0: this.dockerMessages["signatureLabel_Signature0_Param0"],
signatureLabel_Signature1_Param1: this.dockerMessages["signatureLabel_Signature0_Param1"],
signatureLabel_Signature2: this.dockerMessages["signatureLabel_Signature0"],
signatureLabel_Signature2_Param0: this.dockerMessages["signatureLabel_Signature0_Param0"],
signatureLabel_Signature2_Param1: this.dockerMessages["signatureLabel_Signature0_Param1"],
signatureLabel_Signature2_Param2: this.dockerMessages["signatureLabel_Signature0_Param0"],
signatureLabel_Signature2_Param3: this.dockerMessages["signatureLabel_Signature0_Param1"],
signatureMaintainer: this.dockerMessages["signatureMaintainer"],
signatureMaintainer_Param: this.dockerMessages["signatureMaintainer_Param"],
signatureOnbuild: this.dockerMessages["signatureOnbuild"],
signatureOnbuild_Param: this.dockerMessages["signatureOnbuild_Param"],
signatureRun_Signature0: this.dockerMessages["signatureRun_Signature0"],
signatureRun_Signature0_Param0: this.dockerMessages["signatureRun_Signature0_Param0"],
signatureRun_Signature0_Param1: this.dockerMessages["signatureRun_Signature0_Param1"],
signatureRun_Signature0_Param2: this.dockerMessages["signatureRun_Signature0_Param1"],
signatureRun_Signature1: this.dockerMessages["signatureRun_Signature1"],
signatureRun_Signature1_Param1: this.dockerMessages["signatureRun_Signature0_Param0"],
signatureRun_Signature1_Param2: this.dockerMessages["signatureRun_Signature0_Param1"],
signatureRun_Signature1_Param3: this.dockerMessages["signatureRun_Signature0_Param1"],
signatureShell: this.dockerMessages["signatureShell"],
signatureShell_Param1: this.dockerMessages["signatureShell_Param1"],
signatureShell_Param2: this.dockerMessages["signatureShell_Param2"],
signatureShell_Param3: this.dockerMessages["signatureShell_Param2"],
signatureStopsignal: this.dockerMessages["signatureStopsignal"],
signatureStopsignal_Param: this.dockerMessages["signatureStopsignal_Param"],
signatureUser_Signature0: this.dockerMessages["signatureUser_Signature0"],
signatureUser_Signature0_Param: this.dockerMessages["signatureUser_Signature0_Param"],
signatureUser_Signature1: this.dockerMessages["signatureUser_Signature1"],
signatureUser_Signature1_Param0: this.dockerMessages["signatureUser_Signature0"],
signatureUser_Signature1_Param1: this.dockerMessages["signatureUser_Signature1_Param1"],
signatureUser_Signature2: this.dockerMessages["signatureUser_Signature2"],
signatureUser_Signature2_Param: this.dockerMessages["signatureUser_Signature2_Param"],
signatureUser_Signature3: this.dockerMessages["signatureUser_Signature3"],
signatureUser_Signature3_Param0: this.dockerMessages["signatureUser_Signature2_Param"],
signatureUser_Signature3_Param1: this.dockerMessages["signatureUser_Signature3_Param1"],
signatureVolume_Signature0: this.dockerMessages["signatureVolume_Signature0"],
signatureVolume_Signature0_Param0: this.dockerMessages["signatureVolume_Signature0_Param0"],
signatureVolume_Signature0_Param1: this.dockerMessages["signatureVolume_Signature0_Param0"],
signatureVolume_Signature1: this.dockerMessages["signatureVolume_Signature0"],
signatureVolume_Signature1_Param1: this.dockerMessages["signatureVolume_Signature0_Param0"],
signatureVolume_Signature1_Param2: this.dockerMessages["signatureVolume_Signature0_Param0"],
signatureWorkdir: this.dockerMessages["signatureWorkdir"],
signatureWorkdir_Param: this.dockerMessages["signatureWorkdir_Param"]
};

@@ -104,0 +308,0 @@ }

@@ -19,29 +19,34 @@ "use strict";

ValidationCode[ValidationCode["ARGUMENT_REQUIRES_TWO"] = 5] = "ARGUMENT_REQUIRES_TWO";
ValidationCode[ValidationCode["ARGUMENT_REQUIRES_ONE_OR_THREE"] = 6] = "ARGUMENT_REQUIRES_ONE_OR_THREE";
ValidationCode[ValidationCode["ARGUMENT_UNNECESSARY"] = 7] = "ARGUMENT_UNNECESSARY";
ValidationCode[ValidationCode["DUPLICATE_NAME"] = 8] = "DUPLICATE_NAME";
ValidationCode[ValidationCode["FLAG_AT_LEAST_ONE"] = 9] = "FLAG_AT_LEAST_ONE";
ValidationCode[ValidationCode["FLAG_DUPLICATE"] = 10] = "FLAG_DUPLICATE";
ValidationCode[ValidationCode["FLAG_INVALID_DURATION"] = 11] = "FLAG_INVALID_DURATION";
ValidationCode[ValidationCode["FLAG_LESS_THAN_1MS"] = 12] = "FLAG_LESS_THAN_1MS";
ValidationCode[ValidationCode["FLAG_MISSING_DURATION"] = 13] = "FLAG_MISSING_DURATION";
ValidationCode[ValidationCode["FLAG_MISSING_VALUE"] = 14] = "FLAG_MISSING_VALUE";
ValidationCode[ValidationCode["NO_SOURCE_IMAGE"] = 15] = "NO_SOURCE_IMAGE";
ValidationCode[ValidationCode["INVALID_ESCAPE_DIRECTIVE"] = 16] = "INVALID_ESCAPE_DIRECTIVE";
ValidationCode[ValidationCode["INVALID_AS"] = 17] = "INVALID_AS";
ValidationCode[ValidationCode["INVALID_PORT"] = 18] = "INVALID_PORT";
ValidationCode[ValidationCode["INVALID_PROTO"] = 19] = "INVALID_PROTO";
ValidationCode[ValidationCode["INVALID_SIGNAL"] = 20] = "INVALID_SIGNAL";
ValidationCode[ValidationCode["INVALID_SYNTAX"] = 21] = "INVALID_SYNTAX";
ValidationCode[ValidationCode["ONBUILD_CHAINING_DISALLOWED"] = 22] = "ONBUILD_CHAINING_DISALLOWED";
ValidationCode[ValidationCode["ONBUILD_TRIGGER_DISALLOWED"] = 23] = "ONBUILD_TRIGGER_DISALLOWED";
ValidationCode[ValidationCode["SHELL_JSON_FORM"] = 24] = "SHELL_JSON_FORM";
ValidationCode[ValidationCode["SHELL_REQUIRES_ONE"] = 25] = "SHELL_REQUIRES_ONE";
ValidationCode[ValidationCode["SYNTAX_MISSING_EQUALS"] = 26] = "SYNTAX_MISSING_EQUALS";
ValidationCode[ValidationCode["SYNTAX_MISSING_NAMES"] = 27] = "SYNTAX_MISSING_NAMES";
ValidationCode[ValidationCode["MULTIPLE_INSTRUCTIONS"] = 28] = "MULTIPLE_INSTRUCTIONS";
ValidationCode[ValidationCode["UNKNOWN_INSTRUCTION"] = 29] = "UNKNOWN_INSTRUCTION";
ValidationCode[ValidationCode["UNKNOWN_FLAG"] = 30] = "UNKNOWN_FLAG";
ValidationCode[ValidationCode["DEPRECATED_MAINTAINER"] = 31] = "DEPRECATED_MAINTAINER";
ValidationCode[ValidationCode["HEALTHCHECK_CMD_ARGUMENT_MISSING"] = 32] = "HEALTHCHECK_CMD_ARGUMENT_MISSING";
ValidationCode[ValidationCode["ARGUMENT_REQUIRES_AT_LEAST_TWO"] = 6] = "ARGUMENT_REQUIRES_AT_LEAST_TWO";
ValidationCode[ValidationCode["ARGUMENT_REQUIRES_ONE_OR_THREE"] = 7] = "ARGUMENT_REQUIRES_ONE_OR_THREE";
ValidationCode[ValidationCode["ARGUMENT_UNNECESSARY"] = 8] = "ARGUMENT_UNNECESSARY";
ValidationCode[ValidationCode["DUPLICATE_BUILD_STAGE_NAME"] = 9] = "DUPLICATE_BUILD_STAGE_NAME";
ValidationCode[ValidationCode["INVALID_BUILD_STAGE_NAME"] = 10] = "INVALID_BUILD_STAGE_NAME";
ValidationCode[ValidationCode["FLAG_AT_LEAST_ONE"] = 11] = "FLAG_AT_LEAST_ONE";
ValidationCode[ValidationCode["FLAG_DUPLICATE"] = 12] = "FLAG_DUPLICATE";
ValidationCode[ValidationCode["FLAG_INVALID_DURATION"] = 13] = "FLAG_INVALID_DURATION";
ValidationCode[ValidationCode["FLAG_LESS_THAN_1MS"] = 14] = "FLAG_LESS_THAN_1MS";
ValidationCode[ValidationCode["FLAG_MISSING_DURATION"] = 15] = "FLAG_MISSING_DURATION";
ValidationCode[ValidationCode["FLAG_MISSING_VALUE"] = 16] = "FLAG_MISSING_VALUE";
ValidationCode[ValidationCode["FLAG_UNKNOWN_UNIT"] = 17] = "FLAG_UNKNOWN_UNIT";
ValidationCode[ValidationCode["NO_SOURCE_IMAGE"] = 18] = "NO_SOURCE_IMAGE";
ValidationCode[ValidationCode["INVALID_ESCAPE_DIRECTIVE"] = 19] = "INVALID_ESCAPE_DIRECTIVE";
ValidationCode[ValidationCode["INVALID_AS"] = 20] = "INVALID_AS";
ValidationCode[ValidationCode["INVALID_PORT"] = 21] = "INVALID_PORT";
ValidationCode[ValidationCode["INVALID_PROTO"] = 22] = "INVALID_PROTO";
ValidationCode[ValidationCode["INVALID_SIGNAL"] = 23] = "INVALID_SIGNAL";
ValidationCode[ValidationCode["INVALID_SYNTAX"] = 24] = "INVALID_SYNTAX";
ValidationCode[ValidationCode["ONBUILD_CHAINING_DISALLOWED"] = 25] = "ONBUILD_CHAINING_DISALLOWED";
ValidationCode[ValidationCode["ONBUILD_TRIGGER_DISALLOWED"] = 26] = "ONBUILD_TRIGGER_DISALLOWED";
ValidationCode[ValidationCode["SHELL_JSON_FORM"] = 27] = "SHELL_JSON_FORM";
ValidationCode[ValidationCode["SHELL_REQUIRES_ONE"] = 28] = "SHELL_REQUIRES_ONE";
ValidationCode[ValidationCode["SYNTAX_MISSING_EQUALS"] = 29] = "SYNTAX_MISSING_EQUALS";
ValidationCode[ValidationCode["SYNTAX_MISSING_NAMES"] = 30] = "SYNTAX_MISSING_NAMES";
ValidationCode[ValidationCode["SYNTAX_MISSING_SINGLE_QUOTE"] = 31] = "SYNTAX_MISSING_SINGLE_QUOTE";
ValidationCode[ValidationCode["SYNTAX_MISSING_DOUBLE_QUOTE"] = 32] = "SYNTAX_MISSING_DOUBLE_QUOTE";
ValidationCode[ValidationCode["MULTIPLE_INSTRUCTIONS"] = 33] = "MULTIPLE_INSTRUCTIONS";
ValidationCode[ValidationCode["UNKNOWN_INSTRUCTION"] = 34] = "UNKNOWN_INSTRUCTION";
ValidationCode[ValidationCode["UNKNOWN_FLAG"] = 35] = "UNKNOWN_FLAG";
ValidationCode[ValidationCode["DEPRECATED_MAINTAINER"] = 36] = "DEPRECATED_MAINTAINER";
ValidationCode[ValidationCode["HEALTHCHECK_CMD_ARGUMENT_MISSING"] = 37] = "HEALTHCHECK_CMD_ARGUMENT_MISSING";
})(ValidationCode = exports.ValidationCode || (exports.ValidationCode = {}));

@@ -124,7 +129,10 @@ var ValidationSeverity;

for (let j = 0; j < args.length; j++) {
let createInvalidDiagnostic = validate(j, args[j].getValue());
if (createInvalidDiagnostic) {
let range = args[j].getRange();
problems.push(createInvalidDiagnostic(range.start, range.end, args[i].getValue()));
let range = args[j].getRange();
let createInvalidDiagnostic = validate(j, args[j].getValue(), range);
if (createInvalidDiagnostic instanceof Function) {
problems.push(createInvalidDiagnostic(range.start, range.end, args[j].getValue()));
}
else if (createInvalidDiagnostic !== null) {
problems.push(createInvalidDiagnostic);
}
}

@@ -200,6 +208,7 @@ return;

for (let range of names[name]) {
problems.push(Validator.createDuplicateName(range, name));
problems.push(Validator.createDuplicateBuildStageName(range, name));
}
}
}
let escapeChar = dockerfile.getEscapeCharacter();
let hasFrom = false;

@@ -217,10 +226,10 @@ for (let instruction of dockerfile.getInstructions()) {

}
this.validateInstruction(keywords, instruction, keyword, problems);
this.validateInstruction(keywords, escapeChar, instruction, keyword, problems);
}
for (let instruction of dockerfile.getOnbuildTriggers()) {
this.validateInstruction(keywords, instruction, instruction.getKeyword(), problems);
this.validateInstruction(keywords, escapeChar, instruction, instruction.getKeyword(), problems);
}
return problems;
}
validateInstruction(keywords, instruction, keyword, problems) {
validateInstruction(keywords, escapeChar, instruction, keyword, problems) {
if (keywords.indexOf(keyword) === -1) {

@@ -275,6 +284,30 @@ let range = instruction.getInstructionRange();

}
if (property.getValue() === null) {
let value = property.getValue();
if (value === null) {
let range = property.getNameRange();
problems.push(Validator.createSyntaxMissingEquals(range.start, range.end, property.getName()));
}
else if (value.charAt(0) === '"') {
let found = false;
for (let i = 1; i < value.length; i++) {
switch (value.charAt(i)) {
case escapeChar:
i++;
break;
case '"':
if (i === value.length - 1) {
found = true;
}
break;
}
}
if (!found) {
let range = property.getValueRange();
problems.push(Validator.createSyntaxMissingDoubleQuote(range.start, range.end, property.getRawValue()));
}
}
else if (value.charAt(0) === '\'' && value.charAt(value.length - 1) !== '\'') {
let range = property.getValueRange();
problems.push(Validator.createSyntaxMissingSingleQuote(range.start, range.end, value));
}
}

@@ -284,7 +317,17 @@ }

case "FROM":
this.checkArguments(instruction, problems, [1, 3], function (index, argument) {
if (index === 1) {
return argument.toUpperCase() === "AS" ? null : Validator.createInvalidAs;
this.checkArguments(instruction, problems, [1, 3], function (index, argument, range) {
switch (index) {
case 1:
return argument.toUpperCase() === "AS" ? null : Validator.createInvalidAs;
case 2:
argument = argument.toLowerCase();
let regexp = new RegExp(/^[a-z]([a-z0-9_\-.]*)*$/);
if (regexp.test(argument)) {
return null;
}
return Validator.createInvalidBuildStageName(range, argument);
;
default:
return null;
}
return null;
}, Validator.createRequiresOneOrThreeArguments);

@@ -294,3 +337,4 @@ break;

let args = instruction.getArguments();
if (args.length === 0) {
const healthcheckFlags = instruction.getFlags();
if (args.length === 0 && healthcheckFlags.length === 0) {
// all instructions are expected to have at least one argument

@@ -326,4 +370,3 @@ let range = instruction.getInstructionRange();

let validFlags = ["interval", "retries", "start-period", "timeout"];
let flags = instruction.getFlags();
for (let flag of flags) {
for (let flag of healthcheckFlags) {
let flagName = flag.getName();

@@ -349,5 +392,5 @@ if (validFlags.indexOf(flagName) === -1) {

}
this.checkFlagValue(flags, validFlags, problems);
this.checkFlagDuration(flags, ["interval", "start-period", "timeout"], problems);
this.checkDuplicateFlags(flags, validFlags, problems);
this.checkFlagValue(healthcheckFlags, validFlags, problems);
this.checkFlagDuration(healthcheckFlags, ["interval", "start-period", "timeout"], problems);
this.checkDuplicateFlags(healthcheckFlags, validFlags, problems);
}

@@ -422,15 +465,17 @@ break;

let copyArgs = instruction.getArguments();
if (copyArgs.length === 0) {
let range = instruction.getInstructionRange();
problems.push(Validator.createMissingArgument(range.start, range.end));
}
else {
let flags = instruction.getFlags();
if (flags.length > 0 && flags[0].getName() !== "from") {
let flags = instruction.getFlags();
if (flags.length > 0) {
if (flags[0].getName() !== "from") {
let range = flags[0].getNameRange();
problems.push(Validator.createFlagUnknown(range.start, range.end, flags[0].getName()));
}
this.checkFlagValue(flags, ["from"], problems);
this.checkDuplicateFlags(flags, ["from"], problems);
}
if (copyArgs.length === 1) {
problems.push(Validator.createCOPYRequiresAtLeastTwoArguments(copyArgs[0].getRange()));
}
else if (copyArgs.length === 0) {
problems.push(Validator.createCOPYRequiresAtLeastTwoArguments(instruction.getInstructionRange()));
}
this.checkFlagValue(flags, ["from"], problems);
this.checkDuplicateFlags(flags, ["from"], problems);
break;

@@ -552,2 +597,6 @@ default:

continue durationParse;
default:
let range = flag.getValueRange();
problems.push(Validator.createFlagUnknownUnit(range, unit, value));
continue flagCheck;
}

@@ -594,2 +643,6 @@ }

break durationParse;
default:
let range = flag.getValueRange();
problems.push(Validator.createFlagUnknownUnit(range, unit, value));
break;
}

@@ -714,4 +767,29 @@ continue flagCheck;

if (quoted) {
if (argsContent.charAt(i + 1) === '"' || argsContent.charAt(i + 1) === '\\') {
i = i + 1;
switch (argsContent.charAt(i + 1)) {
case '"':
case '\\':
i++;
continue;
case ' ':
case '\t':
for (let j = i + 2; j < argsContent.length; j++) {
switch (argsContent.charAt(j)) {
case '\r':
if (argsContent.charAt(j + 1) === '\n') {
j++;
}
case '\n':
i = j;
continue argsCheck;
case ' ':
case '\t':
break;
default:
break argsCheck;
}
}
break;
default:
i++;
continue;
}

@@ -764,5 +842,8 @@ }

}
static getDiagnosticMessage_DuplicateName(name) {
return Validator.formatMessage(Validator.dockerProblems["duplicateName"], name);
static getDiagnosticMessage_DuplicateBuildStageName(name) {
return Validator.formatMessage(Validator.dockerProblems["duplicateBuildStageName"], name);
}
static getDiagnosticMessage_InvalidBuildStageName(name) {
return Validator.formatMessage(Validator.dockerProblems["invalidBuildStageName"], name);
}
static getDiagnosticMessage_FlagAtLeastOne(flagName, flagValue) {

@@ -789,2 +870,5 @@ return Validator.formatMessage(Validator.dockerProblems["flagAtLeastOne"], flagName, flagValue);

}
static getDiagnosticMessage_FlagUnknownUnit(unit, duration) {
return Validator.formatMessage(Validator.dockerProblems["flagUnknownUnit"], unit, duration);
}
static getDiagnosticMessage_InvalidAs() {

@@ -814,2 +898,5 @@ return Validator.dockerProblems["invalidAs"];

}
static getDiagnosticMessage_COPYRequiresAtLeastTwoArguments() {
return Validator.formatMessage(Validator.dockerProblems["instructionRequiresAtLeastTwoArguments"], "COPY");
}
static getDiagnosticMessage_ENVRequiresTwoArguments() {

@@ -836,2 +923,8 @@ return Validator.formatMessage(Validator.dockerProblems["instructionRequiresTwoArguments"], "ENV");

}
static getDiagnosticMessage_SyntaxMissingSingleQuote(key) {
return Validator.formatMessage(Validator.dockerProblems["syntaxMissingSingleQuote"], key);
}
static getDiagnosticMessage_SyntaxMissingDoubleQuote(key) {
return Validator.formatMessage(Validator.dockerProblems["syntaxMissingDoubleQuote"], key);
}
static getDiagnosticMessage_InstructionCasing() {

@@ -861,5 +954,8 @@ return Validator.dockerProblems["instructionCasing"];

}
static createDuplicateName(range, name) {
return Validator.createError(range.start, range.end, Validator.getDiagnosticMessage_DuplicateName(name), ValidationCode.DUPLICATE_NAME);
static createDuplicateBuildStageName(range, name) {
return Validator.createError(range.start, range.end, Validator.getDiagnosticMessage_DuplicateBuildStageName(name), ValidationCode.DUPLICATE_BUILD_STAGE_NAME);
}
static createInvalidBuildStageName(range, name) {
return Validator.createError(range.start, range.end, Validator.getDiagnosticMessage_InvalidBuildStageName(name), ValidationCode.INVALID_BUILD_STAGE_NAME);
}
static createFlagAtLeastOne(start, end, flagName, flagValue) {

@@ -886,2 +982,5 @@ return Validator.createError(start, end, Validator.getDiagnosticMessage_FlagAtLeastOne(flagName, flagValue), ValidationCode.FLAG_AT_LEAST_ONE);

}
static createFlagUnknownUnit(range, unit, duration) {
return Validator.createError(range.start, range.end, Validator.getDiagnosticMessage_FlagUnknownUnit(unit, duration), ValidationCode.FLAG_UNKNOWN_UNIT);
}
static createInvalidAs(start, end) {

@@ -914,2 +1013,5 @@ return Validator.createError(start, end, Validator.getDiagnosticMessage_InvalidAs(), ValidationCode.INVALID_AS);

}
static createCOPYRequiresAtLeastTwoArguments(range) {
return Validator.createError(range.start, range.end, Validator.getDiagnosticMessage_COPYRequiresAtLeastTwoArguments(), ValidationCode.ARGUMENT_REQUIRES_AT_LEAST_TWO);
}
static createENVRequiresTwoArguments(start, end) {

@@ -942,2 +1044,8 @@ return Validator.createError(start, end, Validator.getDiagnosticMessage_ENVRequiresTwoArguments(), ValidationCode.ARGUMENT_REQUIRES_TWO);

}
static createSyntaxMissingSingleQuote(start, end, argument) {
return Validator.createError(start, end, Validator.getDiagnosticMessage_SyntaxMissingSingleQuote(argument), ValidationCode.SYNTAX_MISSING_SINGLE_QUOTE);
}
static createSyntaxMissingDoubleQuote(start, end, argument) {
return Validator.createError(start, end, Validator.getDiagnosticMessage_SyntaxMissingDoubleQuote(argument), ValidationCode.SYNTAX_MISSING_DOUBLE_QUOTE);
}
static createSyntaxMissingNames(start, end, instruction) {

@@ -1016,3 +1124,6 @@ return Validator.createError(start, end, Validator.getDiagnosticMessage_SyntaxMissingNames(instruction), ValidationCode.SYNTAX_MISSING_NAMES);

"syntaxMissingNames": "${0} names can not be blank",
"duplicateName": "duplicate name ${0}",
"syntaxMissingSingleQuote": "failed to process \"${0}\": unexpected end of statement while looking for matching single-quote",
"syntaxMissingDoubleQuote": "failed to process \"${0}\": unexpected end of statement while looking for matching double-quote",
"duplicateBuildStageName": "duplicate name ${0}",
"invalidBuildStageName": "invalid name for build stage: \"${0}\", name can't start with a number or contain symbols",
"flagAtLeastOne": "${0} must be at least 1 (not ${1})",

@@ -1025,2 +1136,3 @@ "flagDuplicate": "Duplicate flag specified: ${0}",

"flagUnknown": "Unknown flag: ${0}",
"flagUnknownUnit": "time: unknown unit ${0} in duration ${1}",
"instructionExtraArgument": "Instruction has an extra argument",

@@ -1030,2 +1142,3 @@ "instructionMissingArgument": "Instruction has no arguments",

"instructionRequiresOneArgument": "${0} requires exactly one argument",
"instructionRequiresAtLeastTwoArguments": "${0} requires at least two arguments",
"instructionRequiresTwoArguments": "${0} must have two arguments",

@@ -1032,0 +1145,0 @@ "instructionUnnecessaryArgument": "${0} takes no arguments",

@@ -14,2 +14,8 @@ "use strict";

}
isAfter(position) {
if (this.range.end.line < position.line) {
return true;
}
return this.range.start.line < position.line ? true : this.range.start.character > position.character;
}
isBefore(position) {

@@ -16,0 +22,0 @@ if (this.range.start.line < position.line) {

@@ -7,16 +7,14 @@ /* --------------------------------------------------------------------------------------------

Object.defineProperty(exports, "__esModule", { value: true });
const arg_1 = require("./instructions/arg");
const cmd_1 = require("./instructions/cmd");
const copy_1 = require("./instructions/copy");
const env_1 = require("./instructions/env");
const entrypoint_1 = require("./instructions/entrypoint");
const from_1 = require("./instructions/from");
const healthcheck_1 = require("./instructions/healthcheck");
const onbuild_1 = require("./instructions/onbuild");
const imageTemplate_1 = require("./imageTemplate");
const docker_1 = require("../docker");
class Dockerfile {
class Dockerfile extends imageTemplate_1.ImageTemplate {
constructor() {
this.comments = [];
super(...arguments);
this.initialInstructions = new imageTemplate_1.ImageTemplate();
this.buildStages = [];
this.directive = null;
this.instructions = [];
/**
* Whether a FROM instruction has been added to this Dockerfile or not.
*/
this.foundFrom = false;
}

@@ -32,110 +30,27 @@ getEscapeCharacter() {

}
addComment(comment) {
this.comments.push(comment);
getInitialARGs() {
return this.initialInstructions.getARGs();
}
getComments() {
return this.comments;
}
addInstruction(instruction) {
this.instructions.push(instruction);
}
getInstructions() {
return this.instructions;
}
/**
* Gets all the ARG instructions that are defined in this Dockerfile.
*/
getARGs() {
let args = [];
for (let instruction of this.instructions) {
if (instruction instanceof arg_1.Arg) {
args.push(instruction);
getContainingImage(position) {
for (let buildStage of this.buildStages) {
if (buildStage.contains(position)) {
return buildStage;
}
}
return args;
return this.initialInstructions;
}
/**
* Gets all the CMD instructions that are defined in this Dockerfile.
*/
getCMDs() {
let cmds = [];
for (let instruction of this.instructions) {
if (instruction instanceof cmd_1.Cmd) {
cmds.push(instruction);
}
addInstruction(instruction) {
if (instruction.getKeyword() === "FROM") {
this.currentBuildStage = new imageTemplate_1.ImageTemplate();
this.buildStages.push(this.currentBuildStage);
this.foundFrom = true;
}
return cmds;
}
/**
* Gets all the COPY instructions that are defined in this Dockerfile.
*/
getCOPYs() {
let copies = [];
for (let instruction of this.instructions) {
if (instruction instanceof copy_1.Copy) {
copies.push(instruction);
}
else if (!this.foundFrom) {
this.initialInstructions.addInstruction(instruction);
}
return copies;
}
/**
* Gets all the ENTRYPOINT instructions that are defined in this Dockerfile.
*/
getENTRYPOINTs() {
let froms = [];
for (let instruction of this.instructions) {
if (instruction instanceof entrypoint_1.Entrypoint) {
froms.push(instruction);
}
if (this.foundFrom) {
this.currentBuildStage.addInstruction(instruction);
}
return froms;
super.addInstruction(instruction);
}
/**
* Gets all the ENV instructions that are defined in this Dockerfile.
*/
getENVs() {
let args = [];
for (let instruction of this.instructions) {
if (instruction instanceof env_1.Env) {
args.push(instruction);
}
}
return args;
}
/**
* Gets all the FROM instructions that are defined in this Dockerfile.
*/
getFROMs() {
let froms = [];
for (let instruction of this.instructions) {
if (instruction instanceof from_1.From) {
froms.push(instruction);
}
}
return froms;
}
/**
* Gets all the HEALTHCHECK instructions that are defined in this Dockerfile.
*/
getHEALTHCHECKs() {
let froms = [];
for (let instruction of this.instructions) {
if (instruction instanceof healthcheck_1.Healthcheck) {
froms.push(instruction);
}
}
return froms;
}
getOnbuildTriggers() {
let triggers = [];
for (let instruction of this.instructions) {
if (instruction instanceof onbuild_1.Onbuild) {
let trigger = instruction.getTriggerInstruction();
if (trigger) {
triggers.push(trigger);
}
}
}
return triggers;
}
setDirective(directive) {

@@ -142,0 +57,0 @@ this.directive = directive;

@@ -11,2 +11,3 @@ /* --------------------------------------------------------------------------------------------

const instruction_1 = require("./instruction");
const jsonInstruction_1 = require("./instructions/jsonInstruction");
const arg_1 = require("./instructions/arg");

@@ -21,5 +22,7 @@ const cmd_1 = require("./instructions/cmd");

const onbuild_1 = require("./instructions/onbuild");
const shell_1 = require("./instructions/shell");
const stopSignal_1 = require("./instructions/stopSignal");
const workdir_1 = require("./instructions/workdir");
const user_1 = require("./instructions/user");
const volume_1 = require("./instructions/volume");
const dockerfile_1 = require("./dockerfile");

@@ -30,2 +33,4 @@ const docker_1 = require("../docker");

switch (instruction.toUpperCase()) {
case "ADD":
return new jsonInstruction_1.JSONInstruction(document, lineRange, escapeChar, instruction, instructionRange);
case "ARG":

@@ -49,2 +54,6 @@ return new arg_1.Arg(document, lineRange, escapeChar, instruction, instructionRange);

return new onbuild_1.Onbuild(document, lineRange, escapeChar, instruction, instructionRange);
case "RUN":
return new jsonInstruction_1.JSONInstruction(document, lineRange, escapeChar, instruction, instructionRange);
case "SHELL":
return new shell_1.Shell(document, lineRange, escapeChar, instruction, instructionRange);
case "STOPSIGNAL":

@@ -56,2 +65,4 @@ return new stopSignal_1.StopSignal(document, lineRange, escapeChar, instruction, instructionRange);

return new user_1.User(document, lineRange, escapeChar, instruction, instructionRange);
case "VOLUME":
return new volume_1.Volume(document, lineRange, escapeChar, instruction, instructionRange);
}

@@ -58,0 +69,0 @@ return new instruction_1.Instruction(document, lineRange, escapeChar, instruction, instructionRange);

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class Flag {
constructor(name, nameRange, value, valueRange) {
constructor(content, range, name, nameRange, value, valueRange) {
this.content = content;
this.range = range;
this.name = name;

@@ -10,2 +12,8 @@ this.nameRange = nameRange;

}
toString() {
return this.content;
}
getRange() {
return this.range;
}
getName() {

@@ -12,0 +20,0 @@ return this.name;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const instruction_1 = require("../instruction");
class Cmd extends instruction_1.Instruction {
const jsonInstruction_1 = require("./jsonInstruction");
class Cmd extends jsonInstruction_1.JSONInstruction {
constructor(document, range, escapeChar, instruction, instructionRange) {

@@ -6,0 +6,0 @@ super(document, range, escapeChar, instruction, instructionRange);

@@ -8,10 +8,22 @@ "use strict";

const vscode_languageserver_1 = require("vscode-languageserver");
const modifiableInstruction_1 = require("./modifiableInstruction");
class Copy extends modifiableInstruction_1.ModifiableInstruction {
const jsonInstruction_1 = require("./jsonInstruction");
class Copy extends jsonInstruction_1.JSONInstruction {
constructor(document, range, escapeChar, instruction, instructionRange) {
super(document, range, escapeChar, instruction, instructionRange);
}
getArgumentsContent() {
const args = this.getArguments();
const flags = this.getFlags();
if (args.length === 0 || flags.length === 0) {
return super.getArgumentsContent();
}
return this.getRangeContent(vscode_languageserver_1.Range.create(args[0].getRange().start, args[args.length - 1].getRange().end));
}
stopSearchingForFlags(argument) {
return argument.indexOf("--") === -1;
}
getFromFlag() {
let flags = super.getFlags();
return flags.length === 1 && flags[0].getName() === "from" ? flags[0] : null;
}
getFromValue() {

@@ -21,12 +33,13 @@ return this.getRangeContent(this.getFromValueRange());

getFromValueRange() {
let range = this.getFromRange();
if (range === null) {
return null;
}
return vscode_languageserver_1.Range.create(vscode_languageserver_1.Position.create(range.start.line, range.start.character + 7), range.end);
const flag = this.getFromFlag();
return flag ? flag.getValueRange() : null;
}
getFromRange() {
let args = this.getArguments();
if (args.length >= 1 && args[0].getValue().toLowerCase().indexOf("--from=") === 0) {
return args[0].getRange();
const flag = this.getFromFlag();
if (flag) {
const valueRange = flag.getValueRange();
if (valueRange) {
const nameRange = flag.getNameRange();
return vscode_languageserver_1.Range.create(nameRange.start.line, nameRange.start.character - 2, valueRange.end.line, valueRange.end.character);
}
}

@@ -33,0 +46,0 @@ return null;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const instruction_1 = require("../instruction");
class Entrypoint extends instruction_1.Instruction {
const jsonInstruction_1 = require("./jsonInstruction");
class Entrypoint extends jsonInstruction_1.JSONInstruction {
constructor(document, range, escapeChar, instruction, instructionRange) {

@@ -6,0 +6,0 @@ super(document, range, escapeChar, instruction, instructionRange);

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/* --------------------------------------------------------------------------------------------
* Copyright (c) Remy Suen. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
const vscode_languageserver_1 = require("vscode-languageserver");
const instruction_1 = require("../instruction");

@@ -8,2 +13,72 @@ class From extends instruction_1.Instruction {

}
getImage() {
return this.getRangeContent(this.getImageRange());
}
/**
* Returns the name of the image that will be used as the base image.
*
* @return the base image's name, or null if unspecified
*/
getImageName() {
let range = this.getImageRange();
if (range) {
let content = this.getRangeContent(range);
let index = content.lastIndexOf(':');
if (index === -1) {
index = content.lastIndexOf('@');
}
return index === -1 ? content : content.substring(0, index);
}
return null;
}
/**
* Returns the range that covers the image argument of this
* instruction. This includes the tag or digest of the image if
* it has been specified by the instruction.
*
* @return the range of the image argument, or null if no image
* has been specified
*/
getImageRange() {
let args = this.getArguments();
return args.length !== 0 ? args[0].getRange() : null;
}
/**
* Returns the range in the document that the tag of the base
* image encompasses.
*
* @return the base image's tag's range in the document, or null
* if no tag has been specified
*/
getImageTagRange() {
let range = this.getImageRange();
if (range) {
let content = this.getRangeContent(range);
if (content.indexOf('@') === -1) {
let index = content.lastIndexOf(':');
if (index !== -1) {
return vscode_languageserver_1.Range.create(range.start.line, range.start.character + index + 1, range.end.line, range.end.character);
}
}
}
return null;
}
/**
* Returns the range in the document that the digest of the base
* image encompasses.
*
* @return the base image's digest's range in the document, or null
* if no digest has been specified
*/
getImageDigestRange() {
let range = this.getImageRange();
if (range) {
let content = this.getRangeContent(range);
let index = content.lastIndexOf('@');
if (index !== -1) {
return vscode_languageserver_1.Range.create(range.start.line, range.start.character + index + 1, range.end.line, range.end.character);
}
}
return null;
}
getBuildStage() {

@@ -10,0 +85,0 @@ let range = this.getBuildStageRange();

@@ -14,11 +14,5 @@ "use strict";

let args = this.getArguments();
for (let arg of args) {
let value = arg.getValue().toUpperCase();
if (value === "CMD" || value === "NONE") {
return arg;
}
}
return null;
return args.length !== 0 ? args[0] : null;
}
}
exports.Healthcheck = Healthcheck;

@@ -26,9 +26,9 @@ "use strict";

if (index === -1) {
this.flags.push(new flag_1.Flag(value.substring(2), vscode_languageserver_1.Range.create(range.start.line, range.start.character + 2, range.end.line, range.end.character), null, null));
this.flags.push(new flag_1.Flag(value, range, value.substring(2), vscode_languageserver_1.Range.create(range.start.line, range.start.character + 2, range.end.line, range.end.character), null, null));
}
else if (index === value.length - 1) {
this.flags.push(new flag_1.Flag(value.substring(2, index), vscode_languageserver_1.Range.create(range.start.line, range.start.character + 2, range.end.line, range.end.character - 1), "", vscode_languageserver_1.Range.create(range.end.line, range.end.character, range.end.line, range.end.character)));
this.flags.push(new flag_1.Flag(value, range, value.substring(2, index), vscode_languageserver_1.Range.create(range.start.line, range.start.character + 2, range.end.line, range.end.character - 1), "", vscode_languageserver_1.Range.create(range.end.line, range.end.character, range.end.line, range.end.character)));
}
else {
this.flags.push(new flag_1.Flag(value.substring(2, index), vscode_languageserver_1.Range.create(range.start.line, range.start.character + 2, range.start.line, range.start.character + index), value.substring(index + 1), vscode_languageserver_1.Range.create(range.start.line, range.start.character + index + 1, range.end.line, range.end.character)));
this.flags.push(new flag_1.Flag(value, range, value.substring(2, index), vscode_languageserver_1.Range.create(range.start.line, range.start.character + 2, range.start.line, range.start.character + index), value.substring(index + 1), vscode_languageserver_1.Range.create(range.start.line, range.start.character + index + 1, range.end.line, range.end.character)));
}

@@ -40,3 +40,14 @@ }

}
getArguments() {
const args = super.getArguments();
const flags = this.getFlags();
if (flags.length === 0) {
return args;
}
for (let i = 0; i < flags.length; i++) {
args.shift();
}
return args;
}
}
exports.ModifiableInstruction = ModifiableInstruction;

@@ -31,5 +31,5 @@ "use strict";

let args = this.getArguments();
return dockerfileParser_1.DockerfileParser.createInstruction(this.document, this.escapeChar, vscode_languageserver_1.Range.create(args[0].getRange().start, args[args.length - 1].getRange().end), this.getTriggerWord(), triggerRange);
return dockerfileParser_1.DockerfileParser.createInstruction(this.document, this.escapeChar, vscode_languageserver_1.Range.create(args[0].getRange().start, this.getRange().end), this.getTriggerWord(), triggerRange);
}
}
exports.Onbuild = Onbuild;

@@ -105,2 +105,4 @@ "use strict";

}
// records whether the parser has just processed an escaped newline or not
let escaped = false;
let end = this.findTrailingNonWhitespace(fullArgs);

@@ -130,2 +132,3 @@ content = fullArgs.substring(start, end + 1);

// whitespace only, safe to skip
escaped = true;
i = j;

@@ -153,2 +156,3 @@ continue argumentLoop;

// immediately followed by a newline, skip the newline
escaped = true;
i = i + 1;

@@ -177,7 +181,11 @@ continue argumentLoop;

for (let j = i + 1; j < content.length; j++) {
if (content.charAt(j) === char) {
args.push(new argument_1.Argument(content.substring(argStart, j + 1), vscode_languageserver_1.Range.create(this.document.positionAt(instructionNameEndOffset + start + argStart), this.document.positionAt(instructionNameEndOffset + start + j + 1))));
i = j;
argStart = -1;
continue argumentLoop;
switch (content.charAt(j)) {
case char:
args.push(new argument_1.Argument(content.substring(argStart, j + 1), vscode_languageserver_1.Range.create(this.document.positionAt(instructionNameEndOffset + start + argStart), this.document.positionAt(instructionNameEndOffset + start + j + 1))));
i = j;
argStart = -1;
continue argumentLoop;
case this.escapeChar:
j++;
break;
}

@@ -188,6 +196,32 @@ }

case '\t':
args.push(new argument_1.Argument(content.substring(argStart, i), vscode_languageserver_1.Range.create(this.document.positionAt(instructionNameEndOffset + start + argStart), this.document.positionAt(instructionNameEndOffset + start + i))));
if (argStart !== -1) {
args.push(new argument_1.Argument(content.substring(argStart, i), vscode_languageserver_1.Range.create(this.document.positionAt(instructionNameEndOffset + start + argStart), this.document.positionAt(instructionNameEndOffset + start + i))));
}
argStart = -1;
break;
case '#':
if (escaped) {
// a newline was escaped and now there's a comment
for (let j = i + 1; j < content.length; j++) {
switch (content.charAt(j)) {
case '\r':
if (content.charAt(j + 1) === '\n') {
j++;
}
case '\n':
i = j;
continue argumentLoop;
}
}
// went to the end without finding a newline,
// the comment was the last line in the instruction,
// just stop parsing
break argumentLoop;
}
else if (argStart === -1) {
argStart = i;
}
break;
default:
escaped = false;
if (argStart === -1) {

@@ -194,0 +228,0 @@ argStart = i;

@@ -13,9 +13,11 @@ "use strict";

this.value = null;
this.document = document;
this.escapeChar = escapeChar;
if (arg2) {
this.nameRange = arg.getRange();
this.name = document.getText().substring(document.offsetAt(this.nameRange.start), document.offsetAt(this.nameRange.end));
let valueRange = arg2.getRange();
let value = document.getText().substring(document.offsetAt(valueRange.start), document.offsetAt(valueRange.end));
this.valueRange = arg2.getRange();
let value = document.getText().substring(document.offsetAt(this.valueRange.start), document.offsetAt(this.valueRange.end));
this.value = Property.getValue(value, escapeChar);
this.range = vscode_languageserver_1.Range.create(this.nameRange.start, valueRange.end);
this.range = vscode_languageserver_1.Range.create(this.nameRange.start, this.valueRange.end);
}

@@ -25,5 +27,5 @@ else {

this.name = document.getText().substring(document.offsetAt(this.nameRange.start), document.offsetAt(this.nameRange.end));
let valueRange = Property.getValueRange(document, escapeChar, arg);
if (valueRange) {
let value = document.getText().substring(document.offsetAt(valueRange.start), document.offsetAt(valueRange.end));
this.valueRange = Property.getValueRange(document, escapeChar, arg);
if (this.valueRange) {
let value = document.getText().substring(document.offsetAt(this.valueRange.start), document.offsetAt(this.valueRange.end));
this.value = Property.getValue(value, escapeChar);

@@ -46,2 +48,61 @@ }

}
getValueRange() {
return this.valueRange;
}
isInName(position) {
return docker_1.Util.isInsideRange(position, this.nameRange);
}
isNameBefore(position) {
if (this.isInName(position)) {
return false;
}
else if (this.nameRange.start.line < position.line) {
return true;
}
return this.nameRange.start.line === position.line ? this.nameRange.end.character < position.character : false;
}
isValueBefore(position) {
if (this.valueRange === null) {
return false;
}
else if (this.valueRange.start.line < position.line) {
return true;
}
return this.valueRange.start.line === position.line ? this.valueRange.end.character < position.character : false;
}
isInValue(position) {
return this.valueRange === null ? false : docker_1.Util.isInsideRange(position, this.valueRange);
}
getRawValue() {
let rawValue = "";
let value = this.document.getText().substring(this.document.offsetAt(this.valueRange.start), this.document.offsetAt(this.valueRange.end));
rawLoop: for (let i = 0; i < value.length; i++) {
let char = value.charAt(i);
if (char === this.escapeChar) {
for (let j = i + 1; j < value.length; j++) {
switch (value.charAt(j)) {
case '\r':
if (value.charAt(j + 1) === '\n') {
j++;
}
case '\n':
i = j;
continue rawLoop;
case ' ':
case '\t':
break;
default:
rawValue = rawValue + char;
continue rawLoop;
}
}
// this happens if there's only whitespace after the escape character
rawValue = rawValue + char;
}
else {
rawValue = rawValue + char;
}
}
return rawValue;
}
static getNameRange(document, arg) {

@@ -62,10 +123,9 @@ let index = arg.getValue().indexOf('=');

}
// trim the leading whitespace of the variable's value
let startIndex = index < argValue.length - 1 ? docker_1.Util.findLeadingNonWhitespace(argValue.substring(index + 1), escapeChar) : 0;
return vscode_languageserver_1.Range.create(document.positionAt(document.offsetAt(arg.getRange().start) + index + startIndex + 1), document.positionAt(document.offsetAt(arg.getRange().end)));
return vscode_languageserver_1.Range.create(document.positionAt(document.offsetAt(arg.getRange().start) + index + 1), document.positionAt(document.offsetAt(arg.getRange().end)));
}
/**
* Returns the actual value of this ARG instruction's declared
* Returns the actual value of this instruction's declared
* variable. The value will have its escape characters removed if
* applicable.
* applicable. If the value spans multiple lines and there are
* comments nested within the lines, they too will be removed.
*

@@ -78,86 +138,164 @@ * @return the value that this ARG instruction's declared

static getValue(value, escapeChar) {
let literal = false;
let escaped = false;
const skip = docker_1.Util.findLeadingNonWhitespace(value, escapeChar);
if (skip !== 0 && value.charAt(skip) === '#') {
// need to skip over comments
escaped = true;
}
value = value.substring(skip);
let first = value.charAt(0);
let last = value.charAt(value.length - 1);
if ((first === '"' && last === '"') || (first === '\'' && last === '\'')) {
literal = true;
let literal = first === '\'' || first === '"';
let inSingle = (first === '\'' && last === '\'');
let inDouble = false;
if (first === '"') {
for (let i = 1; i < value.length; i++) {
if (value.charAt(i) === escapeChar) {
i++;
}
else if (value.charAt(i) === '"' && i === value.length - 1) {
inDouble = true;
}
}
}
if (inSingle || inDouble) {
value = value.substring(1, value.length - 1);
}
let commentCheck = -1;
let escapedValue = "";
parseValue: for (let i = 0; i < value.length; i++) {
let char = value.charAt(i);
if (char === escapeChar) {
if (i + 1 === value.length) {
switch (char) {
case ' ':
case '\t':
if (escaped && commentCheck === -1) {
commentCheck = i;
}
escapedValue = escapedValue + char;
break;
}
char = value.charAt(i + 1);
if (literal) {
if (char === '\n') {
i++;
case escapeChar:
if (i + 1 === value.length) {
if (literal) {
escapedValue = escapedValue + escapeChar;
}
break;
}
else {
if (char === escapeChar) {
i++;
char = value.charAt(i + 1);
if (char === ' ' || char === '\t') {
whitespaceCheck: for (let j = i + 2; j < value.length; j++) {
let char2 = value.charAt(j);
switch (char2) {
case ' ':
case '\t':
break;
case '\r':
if (value.charAt(j + 1) === '\n') {
j++;
}
case '\n':
escaped = true;
i = j;
continue parseValue;
default:
if (!inDouble && !inSingle && !literal) {
if (char2 === escapeChar) {
// add the escaped character
escapedValue = escapedValue + char;
// now start parsing from the next escape character
i = i + 1;
}
else {
// the expectation is that this j = i + 2 here
escapedValue = escapedValue + char + char2;
i = j;
}
continue parseValue;
}
break whitespaceCheck;
}
}
escapedValue = escapedValue + escapeChar;
}
continue parseValue;
}
else if (char === escapeChar) {
// double escape, append one and move on
escapedValue = escapedValue + escapeChar;
i++;
}
else if (char === '\r') {
if (value.charAt(i + 2) === '\n') {
i++;
}
i++;
}
else if (char === '\n') {
i++;
}
else if (char === ' ' || char === '\t') {
for (let j = i + 2; j < value.length; j++) {
let char2 = value.charAt(j);
if (char2 === ' ' || char2 === '\t') {
continue;
if (inDouble) {
if (char === '\r') {
escaped = true;
i = i + 2;
}
else if (char2 === '\r') {
if (value.charAt(j + 1) === '\n') {
i = j + 1;
else if (char === '\n') {
escaped = true;
i++;
}
else if (char !== '"') {
if (char === escapeChar) {
i++;
}
else {
i = j;
}
continue parseValue;
escapedValue = escapedValue + escapeChar;
}
else if (char2 === '\n') {
// the expectation is that this is === '\n'
i = j;
continue parseValue;
continue parseValue;
}
else if (inSingle || literal) {
if (char === '\r') {
escaped = true;
i = i + 2;
}
else if (char2 === escapeChar) {
// add the escaped character
escapedValue = escapedValue + char;
// now start parsing from the next escape character
i = i + 1;
else if (char === '\n') {
escaped = true;
i++;
}
else {
// the expectation is that this j = i + 2 here
escapedValue = escapedValue + char + char2;
i = j;
continue parseValue;
escapedValue = escapedValue + escapeChar;
}
continue parseValue;
}
}
else {
// any other escapes are simply ignored
else if (char === escapeChar) {
// double escape, append one and move on
escapedValue = escapedValue + escapeChar;
i++;
}
else if (char === '\r') {
if (value.charAt(i + 2) === '\n') {
i++;
}
escaped = true;
i++;
}
else if (char === '\n') {
escaped = true;
i++;
}
else {
// any other escapes are simply ignored
escapedValue = escapedValue + char;
i++;
}
break;
case '#':
// a newline was escaped and now there's a comment
if (escaped) {
if (commentCheck !== -1) {
// rollback and remove the whitespace that was previously appended
escapedValue = escapedValue.substring(0, escapedValue.length - (i - commentCheck));
commentCheck = -1;
}
for (let j = i + 1; j < value.length; j++) {
switch (value.charAt(j)) {
case '\r':
j++;
case '\n':
i = j;
continue parseValue;
}
}
// went to the end without finding a newline,
// the comment was the last line in the instruction,
// just stop parsing
break parseValue;
}
default:
if (escaped) {
escaped = false;
commentCheck = -1;
}
escapedValue = escapedValue + char;
i++;
}
break;
}
else {
escapedValue = escapedValue + char;
}
}

@@ -164,0 +302,0 @@ return escapedValue;

@@ -14,2 +14,3 @@ /* --------------------------------------------------------------------------------------------

const dockerPlainText_1 = require("./dockerPlainText");
const dockerSignatures_1 = require("./dockerSignatures");
const dockerSymbols_1 = require("./dockerSymbols");

@@ -20,2 +21,3 @@ const dockerFormatter_1 = require("./dockerFormatter");

const dockerDefinition_1 = require("./dockerDefinition");
const dockerRegistryClient_1 = require("./dockerRegistryClient");
const docker_1 = require("./docker");

@@ -29,4 +31,6 @@ let markdown = new dockerMarkdown_1.MarkdownDocumentation();

let documentationResolver = new dockerPlainText_1.PlainTextDocumentation();
let signatureHelp = new dockerSignatures_1.DockerSignatures();
let validatorSettings = null;
let connection = vscode_languageserver_1.createConnection();
let dockerRegistryClient = new dockerRegistryClient_1.DockerRegistryClient(connection);
let snippetSupport = false;

@@ -51,3 +55,4 @@ let documents = {};

' ',
'$'
'$',
'-',
]

@@ -75,3 +80,12 @@ },

renameProvider: true,
definitionProvider: true
definitionProvider: true,
signatureHelpProvider: {
triggerCharacters: [
'-',
'[',
',',
' ',
'='
]
}
}

@@ -128,3 +142,3 @@ };

if (document) {
let assist = new dockerAssist_1.DockerAssist(document, snippetSupport);
let assist = new dockerAssist_1.DockerAssist(document, snippetSupport, dockerRegistryClient);
return assist.computeProposals(document, textDocumentPosition.position);

@@ -134,2 +148,13 @@ }

});
connection.onSignatureHelp((textDocumentPosition) => {
let document = documents[textDocumentPosition.textDocument.uri];
if (document !== null) {
return signatureHelp.computeSignatures(document, textDocumentPosition.position);
}
return {
signatures: [],
activeSignature: null,
activeParameter: null,
};
});
connection.onCompletionResolve((item) => {

@@ -136,0 +161,0 @@ if (!item.documentation) {

@@ -11,3 +11,3 @@ {

],
"version": "0.0.6",
"version": "0.0.7",
"author": "Remy Suen",

@@ -43,5 +43,4 @@ "license": "MIT",

"nyc-ci": "nyc --cache false mocha out/test",
"compile": "installServerIntoExtension ../vscode-docker-lsp ./package.json ./tsconfig.vscode.json && tsc --watch -p ./tsconfig.vscode.json",
"coverage": "nyc report --reporter=text-lcov | coveralls"
}
}

@@ -20,2 +20,3 @@ # Dockerfile language server

- rename
- signature help

@@ -22,0 +23,0 @@ ## Development Instructions