1981 changed files with 0 additions and 1346428 deletions
@ -1,2 +0,0 @@ |
|||||||
/lib |
|
||||||
node_modules |
|
@ -1,4 +0,0 @@ |
|||||||
{ |
|
||||||
"extends": ["josa-typescript"] |
|
||||||
} |
|
||||||
|
|
@ -1,18 +0,0 @@ |
|||||||
name: Main |
|
||||||
|
|
||||||
on: push |
|
||||||
|
|
||||||
jobs: |
|
||||||
main: |
|
||||||
runs-on: ${{ matrix.os }} |
|
||||||
strategy: |
|
||||||
matrix: |
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest] |
|
||||||
node: [10, 12, 14] |
|
||||||
steps: |
|
||||||
- uses: "actions/checkout@v2" |
|
||||||
- uses: "actions/setup-node@v1" |
|
||||||
with: { node-version: "${{ matrix.node }}" } |
|
||||||
- run: yarn --frozen-lockfile |
|
||||||
- run: yarn build |
|
||||||
- run: yarn lint |
|
@ -1,21 +0,0 @@ |
|||||||
MIT License |
|
||||||
|
|
||||||
Copyright (c) 2019 Josa Gesell |
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|
||||||
of this software and associated documentation files (the "Software"), to deal |
|
||||||
in the Software without restriction, including without limitation the rights |
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
||||||
copies of the Software, and to permit persons to whom the Software is |
|
||||||
furnished to do so, subject to the following conditions: |
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all |
|
||||||
copies or substantial portions of the Software. |
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
||||||
SOFTWARE. |
|
@ -1,29 +0,0 @@ |
|||||||
# coc-docker |
|
||||||
|
|
||||||
Docker language server extension using [`dockerfile-language-server-nodejs`](https://github.com/rcjsuen/dockerfile-language-server-nodejs) |
|
||||||
for [`coc.nvim`](https://github.com/neoclide/coc.nvim). |
|
||||||
|
|
||||||
## Install |
|
||||||
|
|
||||||
In your vim/neovim, run command: |
|
||||||
|
|
||||||
:CocInstall coc-docker |
|
||||||
|
|
||||||
## Features |
|
||||||
|
|
||||||
See [`dockerfile-language-server-nodejs`](https://github.com/rcjsuen/dockerfile-language-server-nodejs) |
|
||||||
|
|
||||||
## Configuration options |
|
||||||
|
|
||||||
- `docker.enable` set to `false` to disable language server. |
|
||||||
|
|
||||||
Trigger completion in `coc-settings.json` to get complete list. |
|
||||||
|
|
||||||
## Development |
|
||||||
|
|
||||||
1. Run `yarn build` or `yarn build:watch` |
|
||||||
2. Link extension: `yarn run link` / `yarn run unlink` |
|
||||||
|
|
||||||
## License |
|
||||||
|
|
||||||
[MIT © Josa Gesell](LICENSE) |
|
@ -1,62 +0,0 @@ |
|||||||
/*--------------------------------------------------------------------------------------------- |
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved. |
|
||||||
* Licensed under the MIT License. See LICENSE.md in the project root for license information. |
|
||||||
*--------------------------------------------------------------------------------------------*/ |
|
||||||
'use strict'; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
exports.DockerComposeCompletionItemProvider = void 0; |
|
||||||
const tslib_1 = require("tslib"); |
|
||||||
const coc_nvim_1 = require("coc.nvim"); |
|
||||||
const dockerComposeKeyInfo_1 = tslib_1.__importDefault(require("./dockerComposeKeyInfo")); |
|
||||||
const suggestSupportHelper_1 = require("../utils/suggestSupportHelper"); |
|
||||||
class DockerComposeCompletionItemProvider { |
|
||||||
async provideCompletionItems(textDocument, position, token, context) { |
|
||||||
const hub = new suggestSupportHelper_1.SuggestSupportHelper(); |
|
||||||
// Determine the schema version of the current compose file,
|
|
||||||
// based on the existence of a top-level "version" property.
|
|
||||||
const versionMatch = textDocument.getText().match(/^version:\s*(["'])(\d+(\.\d)?)\1/im); |
|
||||||
const version = versionMatch ? versionMatch[2] : "1"; |
|
||||||
const document = coc_nvim_1.workspace.getDocument(textDocument.uri); |
|
||||||
// Get the line where intellisense was invoked on (e.g. 'image: u').
|
|
||||||
const line = await coc_nvim_1.workspace.getLine(textDocument.uri, position.line); |
|
||||||
if (line.length === 0) { |
|
||||||
// empty line
|
|
||||||
return Promise.resolve(this.suggestKeys('', version)); |
|
||||||
} |
|
||||||
const range = document.getWordRangeAtPosition(position); |
|
||||||
// Get the text where intellisense was invoked on (e.g. 'u').
|
|
||||||
const word = range && textDocument.getText(range); |
|
||||||
const textBefore = line.substring(0, position.character); |
|
||||||
if (/^\s*[\w_]*$/.test(textBefore)) { |
|
||||||
// on the first token
|
|
||||||
return Promise.resolve(this.suggestKeys(word, version)); |
|
||||||
} |
|
||||||
// Matches strings like: 'image: "ubuntu'
|
|
||||||
const imageTextWithQuoteMatchYaml = textBefore.match(/^\s*image\s*:\s*"([^"]*)$/); |
|
||||||
if (imageTextWithQuoteMatchYaml) { |
|
||||||
const imageText = imageTextWithQuoteMatchYaml[1]; |
|
||||||
return hub.suggestImages(imageText); |
|
||||||
} |
|
||||||
// Matches strings like: 'image: ubuntu'
|
|
||||||
const imageTextWithoutQuoteMatch = textBefore.match(/^\s*image\s*:\s*([\w:/]*)/); |
|
||||||
if (imageTextWithoutQuoteMatch) { |
|
||||||
const imageText = imageTextWithoutQuoteMatch[1]; |
|
||||||
return hub.suggestImages(imageText); |
|
||||||
} |
|
||||||
return Promise.resolve([]); |
|
||||||
} |
|
||||||
suggestKeys(word, version) { |
|
||||||
// Attempt to grab the keys for the requested schema version,
|
|
||||||
// otherwise, fall back to showing a composition of all possible keys.
|
|
||||||
const keys = dockerComposeKeyInfo_1.default[`v${version}`] || dockerComposeKeyInfo_1.default.All; |
|
||||||
return Object.keys(keys).map(ruleName => { |
|
||||||
const completionItem = { label: ruleName }; |
|
||||||
completionItem.kind = coc_nvim_1.CompletionItemKind.Keyword; |
|
||||||
completionItem.insertText = ruleName + ': '; |
|
||||||
completionItem.documentation = keys[ruleName]; |
|
||||||
return completionItem; |
|
||||||
}); |
|
||||||
} |
|
||||||
} |
|
||||||
exports.DockerComposeCompletionItemProvider = DockerComposeCompletionItemProvider; |
|
||||||
//# sourceMappingURL=dockerComposeCompletionItemProvider.js.map
|
|
@ -1,162 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
/*--------------------------------------------------------------------------------------------- |
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved. |
|
||||||
* Licensed under the MIT License. See LICENSE.md in the project root for license information. |
|
||||||
*--------------------------------------------------------------------------------------------*/ |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
// Define the keys that are shared between all compose file versions,
|
|
||||||
// regardless of the major/minor version (e.g. v1-v2.1+).
|
|
||||||
// https://docs.docker.com/compose/yml/
|
|
||||||
const DOCKER_COMPOSE_SHARED_KEY_INFO = { |
|
||||||
'build': ("Path to a directory containing a Dockerfile. When the value supplied is a relative path, it is interpreted as relative to the " + |
|
||||||
"location of the yml file itself. This directory is also the build context that is sent to the Docker daemon.\n\n" + |
|
||||||
"Compose will build and tag it with a generated name, and use that image thereafter."), |
|
||||||
'cap_add': ("Add or drop container capabilities. See `man 7 capabilities` for a full list."), |
|
||||||
'cap_drop': ("Add or drop container capabilities. See `man 7 capabilities` for a full list."), |
|
||||||
'cgroup_parent': ("Specify an optional parent cgroup for the container."), |
|
||||||
'command': ("Override the default command."), |
|
||||||
'container_name': ("Specify custom container name, rather than a generated default name."), |
|
||||||
'cpu_shares': ("CPU shares (relative weight)."), |
|
||||||
'cpu_quota': ("Limit CPU CFS (Completely Fair Scheduler) quota."), |
|
||||||
'cpuset': ("CPUs in which to allow execution."), |
|
||||||
'devices': ("List of device mappings. Uses the same format as the `--device` docker client create option."), |
|
||||||
'dns': ("Custom DNS servers. Can be a single value or a list."), |
|
||||||
'dns_search': ("Custom DNS search domains. Can be a single value or a list."), |
|
||||||
'dockerfile': ("Alternate Dockerfile. Compose will use an alternate file to build with. Using `dockerfile` together with `image` is not allowed. Attempting to do so results in an error."), |
|
||||||
'domainname': ("Container domain name."), |
|
||||||
'entrypoint': ("Overwrite the default ENTRYPOINT of the image."), |
|
||||||
'env_file': ("Add environment variables from a file. Can be a single value or a list.\n\n" + |
|
||||||
"If you have specified a Compose file with `docker-compose -f FILE`, paths in `env_file` are relative to the directory that file is in.\n\n" + |
|
||||||
"Environment variables specified in `environment` override these values."), |
|
||||||
'environment': ("Add environment variables. You can use either an array or a dictionary.\n\n" + |
|
||||||
"Environment variables with only a key are resolved to their values on the machine Compose is running on, which can be helpful for secret or host-specific values."), |
|
||||||
'expose': ("Expose ports without publishing them to the host machine - they'll only be accessible to linked services. \n" + |
|
||||||
"Only the internal port can be specified."), |
|
||||||
'extends': ("Extend another service, in the current file or another, optionally overriding configuration.\nYou can use `extends` on any service together with other configuration keys. " + |
|
||||||
"The `extends` value must be a dictionary defined with a required `service` and an optional `file` key."), |
|
||||||
'external_links': ("Link to containers started outside this `docker-compose.yml` or even outside of Compose, especially for containers that " + |
|
||||||
"provide shared or common services. `external_links` follow " + |
|
||||||
"semantics similar to `links` when specifying both the container name and the link alias (`CONTAINER:ALIAS`)."), |
|
||||||
'extra_hosts': ("Add hostname mappings. Use the same values as the docker client `--add-host` parameter."), |
|
||||||
'hostname': ("Container host name."), |
|
||||||
'image': ("Tag or partial image ID. Can be local or remote - Compose will attempt to pull if it doesn't exist locally."), |
|
||||||
'ipc': ("IPC namespace to use."), |
|
||||||
'labels': ("Add metadata to containers using Docker labels. You can either use an array or a dictionary.\n" + |
|
||||||
"It's recommended that you use reverse-DNS notation to prevent your labels from conflicting with those used by other software."), |
|
||||||
'links': ("Link to containers in another service. Either specify both the service name and the link alias (`CONTAINER:ALIAS`), or " + |
|
||||||
"just the service name (which will also be used for the alias)."), |
|
||||||
'mac_address': ("Container MAC address (e.g. 92:d0:c6:0a:29:33)."), |
|
||||||
'mem_limit': ("Memory limit."), |
|
||||||
'memswap_limit': ("Swap limit equal to memory plus swap: '-1' to enable unlimited swap."), |
|
||||||
'mem_swappiness': ("Tune container memory swappiness (0 to 100) (default -1)."), |
|
||||||
'pid': ("Sets the PID mode to the host PID mode. This turns on sharing between container and the host operating system the PID address space. " + |
|
||||||
"Containers launched with this flag will be able to access and manipulate other containers in the bare-metal machine's namespace and vise-versa."), |
|
||||||
'ports': ("Expose ports. Either specify both ports (`HOST:CONTAINER`), or just the container port (a random host port will be chosen).\n\n" + |
|
||||||
"**Note**: When mapping ports in the `HOST:CONTAINER` format, you may experience erroneous results when using a container port " + |
|
||||||
"lower than 60, because YAML will parse numbers in the format `xx:yy` as sexagesimal (base 60). For this reason, we recommend " + |
|
||||||
"always explicitly specifying your port mappings as strings."), |
|
||||||
'privileged': ("Give extended privileges to this container."), |
|
||||||
'read_only': ("Mount the container's root filesystem as read only."), |
|
||||||
'restart': ("Restart policy to apply when a container exits (default \"no\")."), |
|
||||||
'security_opt': ("Override the default labeling scheme for each container."), |
|
||||||
'shm_size': ("Size of /dev/shm, default value is 64MB."), |
|
||||||
'stdin_open': ("Keep STDIN open even if not attached."), |
|
||||||
'stop_signal': ("Signal to stop a container, SIGTERM by default."), |
|
||||||
'tty': ("Allocate a pseudo-TTY."), |
|
||||||
'ulimits': ("Override the default ulimits for a container. You can either specify a single limit as an integer or soft/hard limits as a mapping."), |
|
||||||
'user': ("Username or UID (format: <name|uid>[:<group|gid>])."), |
|
||||||
'version': ("Specify the compose format that this file conforms to. Omit this property to indicate v1, otherwise, set this to `2`."), |
|
||||||
'volumes': ("Mount paths as volumes, optionally specifying a path on the host machine (`HOST:CONTAINER`), or an access mode (`HOST:CONTAINER:ro`)."), |
|
||||||
'volume_driver': ("If you use a volume name (instead of a volume path), you may also specify a `volume_driver`."), |
|
||||||
'volumes_from': ("Mount all of the volumes from another service or container."), |
|
||||||
'working_dir': ("Working directory inside the container.") |
|
||||||
}; |
|
||||||
// Define the keys which are unique to the v1 format, and were deprecated in v2+.
|
|
||||||
// https://github.com/docker/compose/blob/master/compose/config/config_schema_v1.json
|
|
||||||
const DOCKER_COMPOSE_V1_KEY_INFO = { |
|
||||||
'log_driver': ("Specify a logging driver for the service's containers, as with the `--log-driver` option for docker run. The default value is json-file."), |
|
||||||
'log_opt': ("Specify logging options with `log_opt` for the logging driver, as with the `--log-opt` option for docker run."), |
|
||||||
'net': ("Networking mode. Use the same values as the docker client `--net` parameter.") |
|
||||||
}; |
|
||||||
// Define the keys which are shared with all v2+ compose file versions, but weren't defined in v1.
|
|
||||||
// https://github.com/docker/compose/blob/master/compose/config/config_schema_v2.0.json
|
|
||||||
const DOCKER_COMPOSE_V2_KEY_INFO = { |
|
||||||
// Added top-level properties
|
|
||||||
'services': ("Specify the set of services that your app is composed of."), |
|
||||||
// TODO: There is now a top-level and service-level volumes/networks setting which conflict.
|
|
||||||
// This will be resolved when we add completion that understands file position context.
|
|
||||||
'networks': ("Specifies the networks to be created as part of your app. This is analogous to running `docker network create`."), |
|
||||||
'volumes': ("Specifies the volumes to be created as part of your app. This is analogous to running `docker volume create`."), |
|
||||||
// Added service-level properties
|
|
||||||
'depends_on': ("Specifies the names of services that this service depends on."), |
|
||||||
'logging': ("Logging configuration for the service."), |
|
||||||
'network_mode': ("Networking mode. Use the same values as the docker client `--net` parameter."), |
|
||||||
'tmpfs': ("Mount a temporary file system inside the container. Can be a single value or a list."), |
|
||||||
// Modified service-level properties
|
|
||||||
'build': ("Configuration options that are applied at build time. Can be specified either as a string containing a path to the build context, or an object with the path specified under `context` and optionally `dockerfile` and `args`."), |
|
||||||
// Added service/logging-level properties
|
|
||||||
// TODO: The "driver" property could be a logging driver, a volume driver,
|
|
||||||
// a network driver, or a network IPAM driver, so we should account for
|
|
||||||
// that when we add context-based completion.
|
|
||||||
'driver': ("Specifies the logging driver to use for the service’s container."), |
|
||||||
'options': ('Options to pass to the specified logging driver, provided as key-value pairs.'), |
|
||||||
// Added service/build-level properties
|
|
||||||
'args': ("Add build arguments, which are environment variables accessible only during the build process."), |
|
||||||
'context': ("Either a path to a directory containing a Dockerfile, or a url to a git repository. This directory will be used as the build context that is sent to the Docker daemon."), |
|
||||||
// Added service/network-level properties
|
|
||||||
'aliases': ("Alternative hostnames for this service on the network. Other containers on the same network can use either the service name or this alias to connect to one of the service’s containers."), |
|
||||||
'ipv4_address': ("Specify a static IPv4 address for containers for this service when joining the network."), |
|
||||||
'ipv6_address': ("Specify a static IPv6 address for containers for this service when joining the network."), |
|
||||||
// Network-level properties
|
|
||||||
'driver_opts': ("Specify a list of options as key-value pairs to pass to the driver. Those options are driver-dependent - consult the driver’s documentation for more information."), |
|
||||||
'external': ("If set to true, specifies that this network has been created outside of Compose. `docker-compose up` will not attempt to create it, and will raise an error if it doesn’t exist."), |
|
||||||
'ipam': ("Specify custom IPAM config"), |
|
||||||
// Network/external-level properties
|
|
||||||
// TODO: This would also apply to an external volume,
|
|
||||||
// so we should account for that when we add context-based completion.
|
|
||||||
'name': ("Specifies the name of the externally defined network."), |
|
||||||
// Network/ipam-level properties
|
|
||||||
'config': ("A list with zero or more config blocks."), |
|
||||||
// Network/ipam/config-level properties
|
|
||||||
'aux_addresses': ("Auxiliary IPv4 or IPv6 addresses used by Network driver, as a mapping from hostname to IP."), |
|
||||||
'gateway': ("IPv4 or IPv6 gateway for the master subnet."), |
|
||||||
'ip_range': ("Range of IPs from which to allocate container IPs."), |
|
||||||
'subnet': ("Subnet in CIDR format that represents a network segment."), |
|
||||||
}; |
|
||||||
// Define the keys which were introduced in the v2.1 format.
|
|
||||||
// https://github.com/docker/compose/blob/master/compose/config/config_schema_v2.1.json
|
|
||||||
const DOCKER_COMPOSE_V2_1_KEY_INFO = { |
|
||||||
// Added service-level properties
|
|
||||||
'group_add': ("Specifies additional groups to join"), |
|
||||||
'isolation': ("Container isolation technology"), |
|
||||||
'oom_score_adj': ("Tune host's OOM preferences (-1000 to 1000)"), |
|
||||||
// Added service/network-level properties
|
|
||||||
'link_local_ips': ("List of IPv4/IPv6 link-local addresses for the container"), |
|
||||||
// Added network-level properties
|
|
||||||
'internal': ("Restrict external access to the network"), |
|
||||||
'enable_ipv6': ("Enable IPv6 networking") |
|
||||||
// Note that in v2.1, networks and volumes can now accept a "labels",
|
|
||||||
// property, however, this label is already defined for services
|
|
||||||
// in the v2.0 format, so we don't need to re-define it.
|
|
||||||
}; |
|
||||||
// Define the keys which were introduced in the v2.2 format.
|
|
||||||
// https://github.com/docker/compose/blob/master/compose/config/config_schema_v2.2.json
|
|
||||||
const DOCKER_COMPOSE_V2_2_KEY_INFO = { |
|
||||||
// Added service-level properties
|
|
||||||
'cpu_count': ("Number of usable CPUs (Windows only)"), |
|
||||||
'cpu_percent': ("Usable percentage of the available CPUs (Windows only)"), |
|
||||||
'cpus': ("CPU quota in number of CPUs") |
|
||||||
}; |
|
||||||
// Helper function that merges the specified version-specific keys with the shared
|
|
||||||
// keys, in order to create a complete schema for a specic version.
|
|
||||||
function mergeWithSharedKeys(...versions) { |
|
||||||
return Object.assign({}, DOCKER_COMPOSE_SHARED_KEY_INFO, ...versions); |
|
||||||
} |
|
||||||
exports.default = { |
|
||||||
v1: mergeWithSharedKeys(DOCKER_COMPOSE_V1_KEY_INFO), |
|
||||||
v2: mergeWithSharedKeys(DOCKER_COMPOSE_V2_KEY_INFO), |
|
||||||
"v2.1": mergeWithSharedKeys(DOCKER_COMPOSE_V2_KEY_INFO, DOCKER_COMPOSE_V2_1_KEY_INFO), |
|
||||||
"v2.2": mergeWithSharedKeys(DOCKER_COMPOSE_V2_KEY_INFO, DOCKER_COMPOSE_V2_1_KEY_INFO, DOCKER_COMPOSE_V2_2_KEY_INFO), |
|
||||||
All: mergeWithSharedKeys(DOCKER_COMPOSE_V1_KEY_INFO, DOCKER_COMPOSE_V2_KEY_INFO, DOCKER_COMPOSE_V2_1_KEY_INFO, DOCKER_COMPOSE_V2_2_KEY_INFO) |
|
||||||
}; |
|
||||||
//# sourceMappingURL=dockerComposeKeyInfo.js.map
|
|
@ -1,3 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
//# sourceMappingURL=types.js.map
|
|
@ -1,30 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
exports.activate = void 0; |
|
||||||
const tslib_1 = require("tslib"); |
|
||||||
const path_1 = tslib_1.__importDefault(require("path")); |
|
||||||
const coc_nvim_1 = require("coc.nvim"); |
|
||||||
const dockerComposeCompletionItemProvider_1 = require("./dockerCompose/dockerComposeCompletionItemProvider"); |
|
||||||
async function activate(context) { |
|
||||||
const config = coc_nvim_1.workspace.getConfiguration().get('docker', {}); |
|
||||||
if (config.enable === false) { |
|
||||||
return; |
|
||||||
} |
|
||||||
const serverModule = require.resolve('dockerfile-language-server-nodejs/lib/server.js'); |
|
||||||
const serverOptions = { |
|
||||||
module: serverModule, |
|
||||||
transport: coc_nvim_1.TransportKind.ipc, |
|
||||||
args: ["--node-ipc"] |
|
||||||
}; |
|
||||||
const clientOptions = { |
|
||||||
documentSelector: ['Dockerfile', 'dockerfile'] |
|
||||||
}; |
|
||||||
const client = new coc_nvim_1.LanguageClient("docker", "dockerfile-language-server-nodejs", serverOptions, clientOptions); |
|
||||||
context.subscriptions.push(coc_nvim_1.services.registLanguageClient(client), coc_nvim_1.commands.registerCommand("docker.version", async () => { |
|
||||||
const v = require(path_1.default.resolve(__dirname, '..', 'package.json')).version; |
|
||||||
coc_nvim_1.window.showMessage(`Version: ${v}`, 'more'); |
|
||||||
})); |
|
||||||
context.subscriptions.push(coc_nvim_1.languages.registerCompletionItemProvider('docker-compose', 'docker', 'yaml.docker-compose', new dockerComposeCompletionItemProvider_1.DockerComposeCompletionItemProvider())); |
|
||||||
} |
|
||||||
exports.activate = activate; |
|
||||||
//# sourceMappingURL=extension.js.map
|
|
@ -1,121 +0,0 @@ |
|||||||
/*--------------------------------------------------------------------------------------------- |
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved. |
|
||||||
* Licensed under the MIT License. See LICENSE.md in the project root for license information. |
|
||||||
*--------------------------------------------------------------------------------------------*/ |
|
||||||
'use strict'; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
exports.SuggestSupportHelper = void 0; |
|
||||||
const tslib_1 = require("tslib"); |
|
||||||
const fs_1 = tslib_1.__importDefault(require("fs")); |
|
||||||
const path_1 = tslib_1.__importDefault(require("path")); |
|
||||||
const coc_nvim_1 = require("coc.nvim"); |
|
||||||
const https_1 = require("https"); |
|
||||||
const pkg = JSON.parse(fs_1.default.readFileSync(path_1.default.join(__dirname, '..', '..', 'package.json'), 'utf-8')); |
|
||||||
class SuggestSupportHelper { |
|
||||||
async suggestImages(word) { |
|
||||||
const results = await searchImagesInRegistryHub(word, true); |
|
||||||
return results.map((image) => { |
|
||||||
const stars = image.star_count > 0 |
|
||||||
? [`${image.star_count} ${image.star_count > 1 ? 'stars' : 'star'}`] |
|
||||||
: []; |
|
||||||
return { |
|
||||||
label: image.name, |
|
||||||
kind: coc_nvim_1.CompletionItemKind.Value, |
|
||||||
detail: tagsForImage(image).concat(stars).join(' '), |
|
||||||
insertText: image.name, |
|
||||||
documentation: image.description, |
|
||||||
}; |
|
||||||
}); |
|
||||||
} |
|
||||||
} |
|
||||||
exports.SuggestSupportHelper = SuggestSupportHelper; |
|
||||||
function tagsForImage(image) { |
|
||||||
const tags = []; |
|
||||||
if (image.is_automated) { |
|
||||||
tags.push('Automated'); |
|
||||||
} |
|
||||||
else if (image.is_trusted) { |
|
||||||
tags.push('Trusted'); |
|
||||||
} |
|
||||||
else if (image.is_official) { |
|
||||||
tags.push('Official'); |
|
||||||
} |
|
||||||
return tags.map(t => `[${t}]`); |
|
||||||
} |
|
||||||
const popular = [ |
|
||||||
{ "is_automated": false, "name": "redis", "is_trusted": false, "is_official": true, "star_count": 1300, "description": "Redis is an open source key-value store that functions as a data structure server." }, |
|
||||||
{ "is_automated": false, "name": "ubuntu", "is_trusted": false, "is_official": true, "star_count": 2600, "description": "Ubuntu is a Debian-based Linux operating system based on free software." }, |
|
||||||
{ "is_automated": false, "name": "wordpress", "is_trusted": false, "is_official": true, "star_count": 582, "description": "The WordPress rich content management system can utilize plugins, widgets, and themes." }, |
|
||||||
{ "is_automated": false, "name": "mysql", "is_trusted": false, "is_official": true, "star_count": 1300, "description": "MySQL is a widely used, open-source relational database management system (RDBMS)." }, |
|
||||||
{ "is_automated": false, "name": "mongo", "is_trusted": false, "is_official": true, "star_count": 1100, "description": "MongoDB document databases provide high availability and easy scalability." }, |
|
||||||
{ "is_automated": false, "name": "centos", "is_trusted": false, "is_official": true, "star_count": 1600, "description": "The official build of CentOS." }, |
|
||||||
{ "is_automated": false, "name": "node", "is_trusted": false, "is_official": true, "star_count": 1200, "description": "Node.js is a JavaScript-based platform for server-side and networking applications." }, |
|
||||||
{ "is_automated": false, "name": "nginx", "is_trusted": false, "is_official": true, "star_count": 1600, "description": "Official build of Nginx." }, |
|
||||||
{ "is_automated": false, "name": "postgres", "is_trusted": false, "is_official": true, "star_count": 1200, "description": "The PostgreSQL object-relational database system provides reliability and data integrity." }, |
|
||||||
{ "is_automated": true, "name": "microsoft/aspnet", "is_trusted": true, "is_official": false, "star_count": 277, "description": "ASP.NET is an open source server-side Web application framework" } |
|
||||||
]; |
|
||||||
async function searchImagesInRegistryHub(prefix, cache) { |
|
||||||
if (prefix.length === 0) { |
|
||||||
// return the popular images if user invoked intellisense
|
|
||||||
// right after typing the keyword and ':' (e.g. 'image:').
|
|
||||||
return Promise.resolve(popular.slice(0)); |
|
||||||
} |
|
||||||
// Do an image search on Docker hub and return the results
|
|
||||||
return (await invokeHubSearch(prefix, 100, cache)).results; |
|
||||||
} |
|
||||||
// https://registry.hub.docker.com/v1/search?q=redis&n=1
|
|
||||||
// {
|
|
||||||
// "num_pages": 10,
|
|
||||||
// "num_results": 10,
|
|
||||||
// "results": [
|
|
||||||
// {
|
|
||||||
// "is_automated": false,
|
|
||||||
// "name": "redis",
|
|
||||||
// "is_trusted": false,
|
|
||||||
// "is_official": true,
|
|
||||||
// "star_count": 830,
|
|
||||||
// "description": "Redis is an open source key-value store that functions as a data structure server."
|
|
||||||
// }
|
|
||||||
// ],
|
|
||||||
// "page_size": 1,
|
|
||||||
// "query": "redis",
|
|
||||||
// "page": 1
|
|
||||||
// }
|
|
||||||
function invokeHubSearch(imageName, count, cache) { |
|
||||||
// https://registry.hub.docker.com/v1/search?q=redis&n=1
|
|
||||||
return httpsRequestJson({ |
|
||||||
hostname: 'registry.hub.docker.com', |
|
||||||
port: 443, |
|
||||||
path: '/v1/search?q=' + encodeURIComponent(imageName) + '&n=' + count, |
|
||||||
method: 'GET', |
|
||||||
}, cache); |
|
||||||
} |
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const JSON_CACHE = {}; |
|
||||||
function httpsRequestJson(opts, cache) { |
|
||||||
if (!cache) { |
|
||||||
return doHttpsRequestJson(opts); |
|
||||||
} |
|
||||||
const cacheKey = `${opts.method} ${opts.hostname} ${opts.path}`; |
|
||||||
if (!JSON_CACHE[cacheKey]) { |
|
||||||
JSON_CACHE[cacheKey] = doHttpsRequestJson(opts); |
|
||||||
} |
|
||||||
// new promise to avoid cancelling
|
|
||||||
return new Promise((resolve, reject) => JSON_CACHE[cacheKey].then(resolve, reject)); |
|
||||||
} |
|
||||||
async function doHttpsRequestJson(opts) { |
|
||||||
opts.headers = Object.assign(Object.assign({}, opts.headers), { 'Accept': 'application/json', 'User-Agent': `coc-docker/${pkg.version}` }); |
|
||||||
return JSON.parse(await httpsRequest(opts)); |
|
||||||
} |
|
||||||
async function httpsRequest(opts) { |
|
||||||
return new Promise((resolve, reject) => { |
|
||||||
const req = https_1.request(opts, (res) => { |
|
||||||
let data = ''; |
|
||||||
res.on('data', (d) => data += d); |
|
||||||
res.on('end', () => resolve(data)); |
|
||||||
}); |
|
||||||
req.end(); |
|
||||||
req.on('error', reject); |
|
||||||
}); |
|
||||||
} |
|
||||||
//# sourceMappingURL=suggestSupportHelper.js.map
|
|
@ -1 +0,0 @@ |
|||||||
../dockerfile-language-server-nodejs/bin/docker-langserver |
|
@ -1 +0,0 @@ |
|||||||
../dockerfile-utils/bin/dockerfile-utils |
|
@ -1 +0,0 @@ |
|||||||
../vscode-languageserver/bin/installServerIntoExtension |
|
@ -1,102 +0,0 @@ |
|||||||
{ |
|
||||||
"name": "coc-docker", |
|
||||||
"version": "0.5.0", |
|
||||||
"lockfileVersion": 2, |
|
||||||
"requires": true, |
|
||||||
"packages": { |
|
||||||
"node_modules/dockerfile-ast": { |
|
||||||
"version": "0.1.0", |
|
||||||
"resolved": "https://registry.npmjs.org/dockerfile-ast/-/dockerfile-ast-0.1.0.tgz", |
|
||||||
"integrity": "sha512-qKftHMVoMliYBaYLkgttm+NXhRISVNkIMfAL4ecmXjiWRElfdfY+xNgITiehG0LpUEDbFUa/UDCByYq/2UZIpQ==", |
|
||||||
"dependencies": { |
|
||||||
"vscode-languageserver-types": "^3.16.0" |
|
||||||
}, |
|
||||||
"engines": { |
|
||||||
"node": "*" |
|
||||||
} |
|
||||||
}, |
|
||||||
"node_modules/dockerfile-language-server-nodejs": { |
|
||||||
"version": "0.2.2", |
|
||||||
"resolved": "https://registry.npmjs.org/dockerfile-language-server-nodejs/-/dockerfile-language-server-nodejs-0.2.2.tgz", |
|
||||||
"integrity": "sha512-PdDtFhzVywa2bZK6OFQhIPMSNPNJQa03Ri3ONxBJpxtOwtAaDSnh95iGj/bdPqQLJGoj1Y/yTheDTxLOTTe5JA==", |
|
||||||
"dependencies": { |
|
||||||
"dockerfile-language-service": "0.1.1", |
|
||||||
"dockerfile-utils": "0.1.1", |
|
||||||
"vscode-languageserver": "^7.0.0" |
|
||||||
}, |
|
||||||
"bin": { |
|
||||||
"docker-langserver": "bin/docker-langserver" |
|
||||||
}, |
|
||||||
"engines": { |
|
||||||
"node": "*" |
|
||||||
} |
|
||||||
}, |
|
||||||
"node_modules/dockerfile-language-service": { |
|
||||||
"version": "0.1.1", |
|
||||||
"resolved": "https://registry.npmjs.org/dockerfile-language-service/-/dockerfile-language-service-0.1.1.tgz", |
|
||||||
"integrity": "sha512-Lw4QlxJoy9F1559wxX+0xe5iSNK95Fbzx/YhdmAzfwgbPvdPzvFouIuuMyMPj/Q5JyFH1QAr7VeagOe24w0cqg==", |
|
||||||
"dependencies": { |
|
||||||
"dockerfile-ast": "0.1.0", |
|
||||||
"dockerfile-utils": "0.1.1", |
|
||||||
"vscode-languageserver-protocol": "^3.16.0", |
|
||||||
"vscode-languageserver-types": "^3.16.0" |
|
||||||
}, |
|
||||||
"engines": { |
|
||||||
"node": "*" |
|
||||||
} |
|
||||||
}, |
|
||||||
"node_modules/dockerfile-utils": { |
|
||||||
"version": "0.1.1", |
|
||||||
"resolved": "https://registry.npmjs.org/dockerfile-utils/-/dockerfile-utils-0.1.1.tgz", |
|
||||||
"integrity": "sha512-ddAA8PCAcT4pBQ1AFRnPjetJ31/7BqNKLHQkZebNE0hBAiOr8SzrnIWvJUcBDHrVbASCVl1Ye37hbaTsUmYHsw==", |
|
||||||
"dependencies": { |
|
||||||
"dockerfile-ast": "0.1.0", |
|
||||||
"vscode-languageserver-types": "^3.16.0" |
|
||||||
}, |
|
||||||
"bin": { |
|
||||||
"dockerfile-utils": "bin/dockerfile-utils" |
|
||||||
}, |
|
||||||
"engines": { |
|
||||||
"node": "*" |
|
||||||
} |
|
||||||
}, |
|
||||||
"node_modules/tslib": { |
|
||||||
"version": "2.3.0", |
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", |
|
||||||
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" |
|
||||||
}, |
|
||||||
"node_modules/vscode-jsonrpc": { |
|
||||||
"version": "6.0.0", |
|
||||||
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz", |
|
||||||
"integrity": "sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg==", |
|
||||||
"engines": { |
|
||||||
"node": ">=8.0.0 || >=10.0.0" |
|
||||||
} |
|
||||||
}, |
|
||||||
"node_modules/vscode-languageserver": { |
|
||||||
"version": "7.0.0", |
|
||||||
"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-7.0.0.tgz", |
|
||||||
"integrity": "sha512-60HTx5ID+fLRcgdHfmz0LDZAXYEV68fzwG0JWwEPBode9NuMYTIxuYXPg4ngO8i8+Ou0lM7y6GzaYWbiDL0drw==", |
|
||||||
"dependencies": { |
|
||||||
"vscode-languageserver-protocol": "3.16.0" |
|
||||||
}, |
|
||||||
"bin": { |
|
||||||
"installServerIntoExtension": "bin/installServerIntoExtension" |
|
||||||
} |
|
||||||
}, |
|
||||||
"node_modules/vscode-languageserver-protocol": { |
|
||||||
"version": "3.16.0", |
|
||||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0.tgz", |
|
||||||
"integrity": "sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A==", |
|
||||||
"dependencies": { |
|
||||||
"vscode-jsonrpc": "6.0.0", |
|
||||||
"vscode-languageserver-types": "3.16.0" |
|
||||||
} |
|
||||||
}, |
|
||||||
"node_modules/vscode-languageserver-types": { |
|
||||||
"version": "3.16.0", |
|
||||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz", |
|
||||||
"integrity": "sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA==" |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,22 +0,0 @@ |
|||||||
name: Node.js Builds |
|
||||||
on: [push] |
|
||||||
jobs: |
|
||||||
build: |
|
||||||
runs-on: ubuntu-latest |
|
||||||
strategy: |
|
||||||
matrix: |
|
||||||
node-version: [10.x, 12.x, 14.x] |
|
||||||
steps: |
|
||||||
- uses: actions/checkout@v2 |
|
||||||
- name: Use Node.js ${{ matrix.node-version }} |
|
||||||
uses: actions/setup-node@v1 |
|
||||||
with: |
|
||||||
node-version: ${{ matrix.node-version }} |
|
||||||
- name: Build |
|
||||||
run: | |
|
||||||
npm install |
|
||||||
npm run build |
|
||||||
- name: Test |
|
||||||
run: | |
|
||||||
npm install coveralls --save-dev |
|
||||||
npm run nyc-ci |
|
@ -1,315 +0,0 @@ |
|||||||
# Changelog |
|
||||||
All notable changes to this project will be documented in this file. |
|
||||||
|
|
||||||
## [0.1.0] - 2020-12-24 |
|
||||||
### Added |
|
||||||
- `Property` |
|
||||||
- `getAssignmentOperator()` ([#86](https://github.com/rcjsuen/dockerfile-ast/issues/86)) |
|
||||||
- `getAssignmentOperatorRange()` ([#86](https://github.com/rcjsuen/dockerfile-ast/issues/86)) |
|
||||||
|
|
||||||
## [0.0.30] - 2020-07-14 |
|
||||||
### Fixed |
|
||||||
- do not consider a single escape character as being an argument for the instruction ([#83](https://github.com/rcjsuen/dockerfile-ast/issues/83)) |
|
||||||
- do not consider a single escape character as being a property for an instruction ([#84](https://github.com/rcjsuen/dockerfile-ast/issues/84)) |
|
||||||
|
|
||||||
## [0.0.29] - 2020-07-12 |
|
||||||
### Fixed |
|
||||||
- ignore leading whitespace before a comment in escaped newlines for `getArgumentsContent()` and `getArgumentsRanges()` of `Instruction` ([#82](https://github.com/rcjsuen/dockerfile-ast/issues/82)) |
|
||||||
|
|
||||||
## [0.0.28] - 2020-07-11 |
|
||||||
### Fixed |
|
||||||
- improve handling of trailing whitespace that is not a newline character after an escape character ([#81](https://github.com/rcjsuen/dockerfile-ast/issues/81)) |
|
||||||
|
|
||||||
## [0.0.27] - 2020-06-17 |
|
||||||
### Fixed |
|
||||||
- allow comments to immediately follow the declaration of an ARG or ENV instruction ([#80](https://github.com/rcjsuen/dockerfile-ast/issues/80)) |
|
||||||
|
|
||||||
## [0.0.26] - 2020-04-22 |
|
||||||
### Fixed |
|
||||||
- correct range of multiline arguments that end with a character preceded by an escape character ([#78](https://github.com/rcjsuen/dockerfile-ast/issues/78)) |
|
||||||
- correct range of arguments that are split on multiple lines with escaped whitespace lines in between ([#77](https://github.com/rcjsuen/dockerfile-ast/issues/77)) |
|
||||||
- enable parsing of flag options that do not have a value defined ([#79](https://github.com/rcjsuen/dockerfile-ast/issues/79)) |
|
||||||
|
|
||||||
## [0.0.25] - 2020-04-01 |
|
||||||
### Added |
|
||||||
- `Flag` |
|
||||||
- `getOptions()` ([#75](https://github.com/rcjsuen/dockerfile-ast/issues/75)) |
|
||||||
- `getOption(string)` ([#75](https://github.com/rcjsuen/dockerfile-ast/issues/75)) |
|
||||||
- `hasOptions()` ([#75](https://github.com/rcjsuen/dockerfile-ast/issues/75)) |
|
||||||
- `FlagOption` ([#75](https://github.com/rcjsuen/dockerfile-ast/issues/75)) |
|
||||||
- `Run` ([#76](https://github.com/rcjsuen/dockerfile-ast/issues/76)) |
|
||||||
- `RUN` instructions will now of type `Run` instead of `JSONInstruction` |
|
||||||
- `Run` extends `JSONInstruction` so this is not be a breaking change |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- allow `From`'s `getBuildStage()` and `getBuildStageRange()` to return non-`null` values even if the instruction has more than three arguments as long as parts of it is valid ([#74](https://github.com/rcjsuen/dockerfile-ast/issues/74)) |
|
||||||
|
|
||||||
## [0.0.24] - 2020-03-08 |
|
||||||
### Fixed |
|
||||||
- `Instruction`'s `getArguments()` will no longer exclude arguments that follow an embedded comment that ends with the escape character ([#73](https://github.com/rcjsuen/dockerfile-ast/issues/73)) |
|
||||||
|
|
||||||
## [0.0.23] - 2020-03-08 |
|
||||||
### Fixed |
|
||||||
- `Instruction`'s `getArguments()` will no longer incorrectly exclude arguments because they look like comments ([#72](https://github.com/rcjsuen/dockerfile-ast/issues/72)) |
|
||||||
|
|
||||||
## [0.0.22] - 2020-03-07 |
|
||||||
### Fixed |
|
||||||
- instructions will no longer be cut off prematurely due to empty continuation lines embedded in the keyword itself ([#70](https://github.com/rcjsuen/dockerfile-ast/issues/70)) |
|
||||||
- `Instruction`'s `getArguments()` will now correctly account for multiple embedded comments instead of considering them as an argument ([#71](https://github.com/rcjsuen/dockerfile-ast/issues/71)) |
|
||||||
|
|
||||||
## [0.0.21] - 2020-02-27 |
|
||||||
### Fixed |
|
||||||
- `Instruction`'s `getArgumentsRanges()` will no longer throw an error if an instruction spans multiple lines and has escaped newlines at the beginning of a line ([#67](https://github.com/rcjsuen/dockerfile-ast/issues/67)) |
|
||||||
- `ModifiableInstruction`'s `toString()` will now include the instruction's flags ([#68](https://github.com/rcjsuen/dockerfile-ast/issues/68)) |
|
||||||
- `ModifiableInstruction`'s `getVariables()` will now include variables that are used in the instruction's flags ([#69](https://github.com/rcjsuen/dockerfile-ast/issues/69)) |
|
||||||
|
|
||||||
## [0.0.20] - 2020-02-11 |
|
||||||
### Added |
|
||||||
- `Dockerfile` |
|
||||||
- `getDirectives()` ([#62](https://github.com/rcjsuen/dockerfile-ast/issues/62)) |
|
||||||
- originally introduced in 0.0.18 to support compatibility in the future, the function is now fully implemented and will return an ordered list of all the parser directives defined at the top of the Dockerfile |
|
||||||
|
|
||||||
- `Directive` |
|
||||||
- `syntax` ([#63](https://github.com/rcjsuen/dockerfile-ast/issues/63)) |
|
||||||
- this enum can be used for identifying the `syntax` parser directive used by BuildKit |
|
||||||
|
|
||||||
### Changed |
|
||||||
- `ParserDirective` |
|
||||||
- `getDirective()` ([#63](https://github.com/rcjsuen/dockerfile-ast/issues/63)) |
|
||||||
- this function originally stated that it would return a `Directive` |
|
||||||
- `undefined` would be returned if the name of the parser directive was not recognized |
|
||||||
- the function now returns `Directive | null` |
|
||||||
- the function will return `null` if the parser directive is not recognized instead of `undefined` |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- `Instruction`'s `getArgumentsRanges()` will no longer throw an error if the instruction has its last argument on its own line with no leading whitespace and the length of that argument is one ([#66](https://github.com/rcjsuen/dockerfile-ast/issues/66)) |
|
||||||
|
|
||||||
## [0.0.19] - 2020-01-27 |
|
||||||
### Added |
|
||||||
- `From` |
|
||||||
- `getPlatformFlag()` ([#65](https://github.com/rcjsuen/dockerfile-ast/issues/65)) |
|
||||||
|
|
||||||
### Changed |
|
||||||
- `From` |
|
||||||
- this class now subclasses `ModifiableInstruction` instead of `Instruction` ([#65](https://github.com/rcjsuen/dockerfile-ast/issues/65)) |
|
||||||
- this was changed to support the `--platform` flag introduced in Docker CE 18.04 |
|
||||||
- as `ModifiableInstruction` extends `Instruction`, this should not impact anyone at an API level from a compilation standpoint |
|
||||||
- note that this will break users that previously used `getArguments()` to parse and retrieve the `--platform` flag manually, please replace such usages with the new `getPlatformFlag()` API |
|
||||||
|
|
||||||
## [0.0.18] - 2019-12-07 |
|
||||||
### Added |
|
||||||
- `Dockerfile` |
|
||||||
- `getDirectives()` ([#64](https://github.com/rcjsuen/dockerfile-ast/issues/64)) |
|
||||||
|
|
||||||
### Changed |
|
||||||
- `getDirective()` of `Dockerfile` has been deprecated and will be replaced by `getDirectives()` in the future ([#64](https://github.com/rcjsuen/dockerfile-ast/issues/64)) |
|
||||||
- note that this is purely a cosmetic API change to facilitate migration at the moment, proper support for returning an array will follow in the future |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- add support for TypeScript 3.7 by fixing TS2440 compiler error ([#61](https://github.com/rcjsuen/dockerfile-ast/issues/61)) |
|
||||||
|
|
||||||
## [0.0.17] - 2019-10-13 |
|
||||||
### Fixed |
|
||||||
- correct parsing of image names that were incorrectly identified as a Docker registry ([#59](https://github.com/rcjsuen/dockerfile-ast/issues/59)) |
|
||||||
|
|
||||||
## [0.0.16] - 2019-05-22 |
|
||||||
### Fixed |
|
||||||
- only allow alphanumeric and underscore characters in variable names ([#58](https://github.com/rcjsuen/dockerfile-ast/issues/58)) |
|
||||||
|
|
||||||
## [0.0.15] - 2019-05-21 |
|
||||||
### Fixed |
|
||||||
- variables in `FROM` should return `true` for `isDefined()` if it is defined in the `ARG` instructions above it ([#56](https://github.com/rcjsuen/dockerfile-ast/issues/56)) |
|
||||||
- variables in `FROM` should return `true` for `isBuildVariable()` if it is defined in the `ARG` instructions above it ([#57](https://github.com/rcjsuen/dockerfile-ast/issues/57)) |
|
||||||
|
|
||||||
## [0.0.14] - 2019-04-28 |
|
||||||
### Added |
|
||||||
- `ImageTemplate` |
|
||||||
- `getRange()` ([#53](https://github.com/rcjsuen/dockerfile-ast/issues/53)) |
|
||||||
|
|
||||||
### Changed |
|
||||||
- the enum value for `Keyword.ADD` was incorrectly assigned to `"ARG"`, it is now assigned to `"ADD"` ([#51](https://github.com/rcjsuen/dockerfile-ast/issues/51)) |
|
||||||
- this is a breaking change but presumably no consumers were relying on this incorrect behaviour |
|
||||||
- `Dockerfile`'s `getContainingImage()` has been changed for comments immediately before a build stage |
|
||||||
- previously, they would return the build stage that came after the comment, now they will simply return the entire Dockerfile |
|
||||||
- this is because the comment is actually ambiguous as it may be a commented out instruction for the build stage that came before the comment |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- correct incorrectly assigned string enum value for `Keyword.ADD` ([#51](https://github.com/rcjsuen/dockerfile-ast/issues/51)) |
|
||||||
- ensure quotation marks and apostrophes are included for expanded arguments in `Instruction`'s `getExpandedArguments()` if they surround a variable ([#52](https://github.com/rcjsuen/dockerfile-ast/issues/52)) |
|
||||||
- fixed `getComments()` for build stages so that they will not simply return empty arrays ([#54](https://github.com/rcjsuen/dockerfile-ast/issues/54)) |
|
||||||
- the returned comments will only be from comments contained within the `FROM` instruction and the last instruction of that build stage |
|
||||||
|
|
||||||
## [0.0.13] - 2018-12-20 |
|
||||||
### Fixed |
|
||||||
- prevent TypeError from being thrown by `Dockerfile`'s `resolveVariable(string, number)` when an invalid line number is provided ([#48](https://github.com/rcjsuen/dockerfile-ast/issues/48)) |
|
||||||
- correct compiler error due to incomplete interface signature ([#46](https://github.com/rcjsuen/dockerfile-ast/issues/46)) |
|
||||||
|
|
||||||
## [0.0.12] - 2018-08-10 |
|
||||||
### Fixed |
|
||||||
- handle quoted properties on separate lines properly for `ENV`s and `LABEL`s ([#44](https://github.com/rcjsuen/dockerfile-ast/issues/45)) |
|
||||||
|
|
||||||
## [0.0.11] - 2018-06-16 |
|
||||||
### Fixed |
|
||||||
- ignore initial `ENV`s when resolving variables in `FROM`s ([#44](https://github.com/rcjsuen/dockerfile-ast/issues/44)) |
|
||||||
|
|
||||||
## [0.0.10] - 2018-06-16 |
|
||||||
### Added |
|
||||||
- `From` |
|
||||||
- `getImageRange()` ([#43](https://github.com/rcjsuen/dockerfile-ast/issues/43)) |
|
||||||
- `getImageTag()` ([#43](https://github.com/rcjsuen/dockerfile-ast/issues/43)) |
|
||||||
- `getImageDigest()` ([#43](https://github.com/rcjsuen/dockerfile-ast/issues/43)) |
|
||||||
- `getRegistry()` ([#43](https://github.com/rcjsuen/dockerfile-ast/issues/43)) |
|
||||||
- `getRegistryRange()` ([#43](https://github.com/rcjsuen/dockerfile-ast/issues/43)) |
|
||||||
|
|
||||||
### Changed |
|
||||||
- [upgraded the dependency of Mocha](https://github.com/mochajs/mocha/issues/2791) from 3.x to 5.x |
|
||||||
- versions prior to 4.x of Mocha dependended on Growl 1.9.2 which contained a [security vulnerability](https://github.com/tj/node-growl/issues/60) |
|
||||||
- as Mocha is a `devDependencies` module, there is no reason to believe that the `dockerfile-ast` module itself was affected by this vulnerability |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- do not resolve reinitialized `ARG` variables with `ENV` instructions at the top of the Dockerfile ([#42](https://github.com/rcjsuen/dockerfile-ast/issues/42)) |
|
||||||
- improve parsing of `FROM` instructions that refer to variables ([#39](https://github.com/rcjsuen/dockerfile-ast/issues/39)) |
|
||||||
|
|
||||||
## [0.0.9] - 2018-05-28 |
|
||||||
### Fixed |
|
||||||
- handle comments in the last line of a file properly for `ARG`, `ENV`, and `LABEL` ([#40](https://github.com/rcjsuen/dockerfile-ast/issues/40)) |
|
||||||
- parse `ARG` instructions properly when its value contains an unclosed quote ([#41](https://github.com/rcjsuen/dockerfile-ast/issues/41)) |
|
||||||
|
|
||||||
## [0.0.8] - 2018-05-27 |
|
||||||
### Fixed |
|
||||||
- prevent `getVariables()` from throwing an error if a `LABEL` has no value defined ([#38](https://github.com/rcjsuen/dockerfile-ast/issues/38)) |
|
||||||
|
|
||||||
## [0.0.7] - 2018-05-25 |
|
||||||
### Added |
|
||||||
- `ParserDirective` |
|
||||||
- `toString()` ([#4](https://github.com/rcjsuen/dockerfile-ast/issues/4)) |
|
||||||
- `PropertyInstruction` |
|
||||||
- `getPropertyArguments()` ([#37](https://github.com/rcjsuen/dockerfile-ast/issues/37)) |
|
||||||
- `Variable` |
|
||||||
- `getModifier()` ([#27](https://github.com/rcjsuen/dockerfile-ast/issues/27)) |
|
||||||
- `getModifierRange()` ([#33](https://github.com/rcjsuen/dockerfile-ast/issues/33)) |
|
||||||
- `getSubstitutionParameter()` ([#27](https://github.com/rcjsuen/dockerfile-ast/issues/27)) |
|
||||||
- `getSubstitutionRange()` ([#33](https://github.com/rcjsuen/dockerfile-ast/issues/33)) |
|
||||||
- `toString()` ([#4](https://github.com/rcjsuen/dockerfile-ast/issues/4)) |
|
||||||
|
|
||||||
### Changed |
|
||||||
- `PropertyInstruction` |
|
||||||
- `getArguments()` ([#34](https://github.com/rcjsuen/dockerfile-ast/issues/34)) |
|
||||||
- to make this function more predictable, `PropertyInstruction` no longer overrides this function with its own implementation, existing callers should call `getPropertyArguments()` instead if the old behaviour is desired |
|
||||||
```TypeScript |
|
||||||
// this function has been changed to possibly not return the same thing |
|
||||||
// depending on the structure of the instruction's arguments |
|
||||||
let args = propertyInstruction.getArguments(); |
|
||||||
// to get the same behaviour in 0.0.6, use getPropertyArguments() instead |
|
||||||
let args = propertyInstruction.getPropertyArguments(); |
|
||||||
``` |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- resolve references to uninitialized `ARG` variables against `ARG` variables before the first `FROM` if present ([#26](https://github.com/rcjsuen/dockerfile-ast/issues/26)) |
|
||||||
- change `FROM` to parse its image argument correctly if it is in a private registry ([#28](https://github.com/rcjsuen/dockerfile-ast/issues/28)) |
|
||||||
- fix parsing issue with quoted keys and values in `ARG`, `ENV`, and `LABEL` ([#30](https://github.com/rcjsuen/dockerfile-ast/issues/30)) |
|
||||||
- ignore equals signs that are found inside quotes ([#29](https://github.com/rcjsuen/dockerfile-ast/issues/29)) |
|
||||||
- prevent arguments from being split up if they span multiple lines via escaped newlines ([#34](https://github.com/rcjsuen/dockerfile-ast/issues/34)) |
|
||||||
- prevent variables from being split up if they span multiple lines via escaped newlines ([#35](https://github.com/rcjsuen/dockerfile-ast/issues/35)) |
|
||||||
|
|
||||||
## [0.0.6] - 2018-04-19 |
|
||||||
### Changed |
|
||||||
- `Property` |
|
||||||
- `getRawValue()` has been renamed to `getUnescapedValue()` ([#25](https://github.com/rcjsuen/dockerfile-ast/issues/25)) |
|
||||||
- the underlying implementation of the function has not changed so it should be easy for clients to migrate to the new API |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- fix parsing of spaces embedded within a variable replacement in `ARG`, `ENV`, and `LABEL` instructions ([#24](https://github.com/rcjsuen/dockerfile-ast/issues/24)) |
|
||||||
|
|
||||||
## [0.0.5] - 2018-04-15 |
|
||||||
### Fixed |
|
||||||
- fix resolution of `ARG` variables that are used in a `FROM` ([#22](https://github.com/rcjsuen/dockerfile-ast/issues/22)) |
|
||||||
- prevent error from being thrown if an invalid line number is specified by `Dockerfile`'s `getAvailableVariables(number)` function ([#23](https://github.com/rcjsuen/dockerfile-ast/issues/23)) |
|
||||||
|
|
||||||
## [0.0.4] - 2018-04-03 |
|
||||||
### Added |
|
||||||
- `JSONArgument extends Argument` ([#20](https://github.com/rcjsuen/dockerfile-ast/issues/20)) |
|
||||||
- `getJSONRange()` |
|
||||||
- `getJSONValue()` |
|
||||||
- `Comment` |
|
||||||
- `toString()` ([#4](https://github.com/rcjsuen/dockerfile-ast/issues/4)) |
|
||||||
|
|
||||||
### Changed |
|
||||||
- `JSONInstruction` |
|
||||||
- `getJSONStrings()` now returns `JSONArgument[]` instead of `Argument[]` |
|
||||||
- since `JSONArgument` extends `Argument`, any existing code should continue to work with no code changes required |
|
||||||
|
|
||||||
## [0.0.3] - 2018-02-10 |
|
||||||
### Added |
|
||||||
- `From` |
|
||||||
- `getImageNameRange()` ([#16](https://github.com/rcjsuen/dockerfile-ast/issues/16)) |
|
||||||
- `Instruction` |
|
||||||
- `toString()` ([#4](https://github.com/rcjsuen/dockerfile-ast/issues/4)) |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- calling `ImageTemplate`'s `getAvailableVariables(number)` with a Dockerfile should only return the variables that are declared in the build stage of the given line ([#15](https://github.com/rcjsuen/dockerfile-ast/issues/15)) |
|
||||||
- correct `From`'s `getImageName()` to return the right name for the image if it is pointing at a digest ([#17](https://github.com/rcjsuen/dockerfile-ast/issues/17)) |
|
||||||
- calling `ImageTemplate`'s `getAvailableVariables(number)` on a line with a `FROM` should return variables defined by the Dockerfile's initial `ARG` instructions (if any) ([#18](https://github.com/rcjsuen/dockerfile-ast/issues/18)) |
|
||||||
|
|
||||||
## [0.0.2] - 2018-01-20 |
|
||||||
### Added |
|
||||||
- `Argument` |
|
||||||
- `toString()` ([#4](https://github.com/rcjsuen/dockerfile-ast/issues/4)) |
|
||||||
- `Variable` |
|
||||||
- `isBuildVariable()` ([#13](https://github.com/rcjsuen/dockerfile-ast/issues/13)) |
|
||||||
- `isDefined()` ([#12](https://github.com/rcjsuen/dockerfile-ast/issues/12)) |
|
||||||
- `isEnvironmentVariable()` ([#13](https://github.com/rcjsuen/dockerfile-ast/issues/13)) |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- restrict variable resolution to the containing build stage ([#14](https://github.com/rcjsuen/dockerfile-ast/issues/14)) |
|
||||||
|
|
||||||
### Removed |
|
||||||
- `Argument`'s `getRawValue()` function has been removed ([#10](https://github.com/rcjsuen/dockerfile-ast/issues/10)) |
|
||||||
```TypeScript |
|
||||||
// this convenience function has been removed |
|
||||||
let rawValue = argument.getRawValue(); |
|
||||||
// to retrieve the identical value, use the following code instead |
|
||||||
import { TextDocument } from 'vscode-languageserver-types'; |
|
||||||
let document = TextDocument.create(uri, languageId, version, buffer); |
|
||||||
let range = argument.getRange(); |
|
||||||
let rawValue = buffer.substring(document.offsetAt(range.start), document.offsetAt(range.end)); |
|
||||||
``` |
|
||||||
|
|
||||||
## 0.0.1 - 2017-12-20 |
|
||||||
### Added |
|
||||||
- Dockerfile parser |
|
||||||
- handles escape characters |
|
||||||
- preserves comments |
|
||||||
- provides variable lookup and resolution |
|
||||||
|
|
||||||
[Unreleased]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.1.0...HEAD |
|
||||||
[0.1.0]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.30...v0.1.0 |
|
||||||
[0.0.30]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.29...v0.0.30 |
|
||||||
[0.0.29]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.28...v0.0.29 |
|
||||||
[0.0.28]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.27...v0.0.28 |
|
||||||
[0.0.27]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.26...v0.0.27 |
|
||||||
[0.0.26]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.25...v0.0.26 |
|
||||||
[0.0.25]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.24...v0.0.25 |
|
||||||
[0.0.24]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.23...v0.0.24 |
|
||||||
[0.0.23]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.22...v0.0.23 |
|
||||||
[0.0.22]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.21...v0.0.22 |
|
||||||
[0.0.21]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.20...v0.0.21 |
|
||||||
[0.0.20]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.19...v0.0.20 |
|
||||||
[0.0.19]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.18...v0.0.19 |
|
||||||
[0.0.18]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.17...v0.0.18 |
|
||||||
[0.0.17]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.16...v0.0.17 |
|
||||||
[0.0.16]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.15...v0.0.16 |
|
||||||
[0.0.15]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.14...v0.0.15 |
|
||||||
[0.0.14]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.13...v0.0.14 |
|
||||||
[0.0.13]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.12...v0.0.13 |
|
||||||
[0.0.12]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.11...v0.0.12 |
|
||||||
[0.0.11]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.10...v0.0.11 |
|
||||||
[0.0.10]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.9...v0.0.10 |
|
||||||
[0.0.9]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.8...v0.0.9 |
|
||||||
[0.0.8]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.7...v0.0.8 |
|
||||||
[0.0.7]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.6...v0.0.7 |
|
||||||
[0.0.6]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.5...v0.0.6 |
|
||||||
[0.0.5]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.4...v0.0.5 |
|
||||||
[0.0.4]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.3...v0.0.4 |
|
||||||
[0.0.3]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.2...v0.0.3 |
|
||||||
[0.0.2]: https://github.com/rcjsuen/dockerfile-ast/compare/v0.0.1...v0.0.2 |
|
@ -1,22 +0,0 @@ |
|||||||
Copyright (c) 2017 Remy Suen |
|
||||||
|
|
||||||
MIT License |
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining |
|
||||||
a copy of this software and associated documentation files (the |
|
||||||
"Software"), to deal in the Software without restriction, including |
|
||||||
without limitation the rights to use, copy, modify, merge, publish, |
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to |
|
||||||
permit persons to whom the Software is furnished to do so, subject to |
|
||||||
the following conditions: |
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be |
|
||||||
included in all copies or substantial portions of the Software. |
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
@ -1,58 +0,0 @@ |
|||||||
# Dockerfile AST |
|
||||||
|
|
||||||
[](https://travis-ci.org/rcjsuen/dockerfile-ast) [](https://coveralls.io/github/rcjsuen/dockerfile-ast?branch=master) [](https://david-dm.org/rcjsuen/dockerfile-ast) [](https://opensource.org/licenses/MIT) [](https://www.npmjs.com/package/dockerfile-ast) |
|
||||||
|
|
||||||
The `dockerfile-ast` NPM module is a Dockerfile parser written in TypeScript. |
|
||||||
The module provides full programmatic access to a parsed Dockerfile. |
|
||||||
|
|
||||||
Supported features: |
|
||||||
- escaped newline detection |
|
||||||
- `escape` parser directive considered when parsing |
|
||||||
- comments preserved |
|
||||||
- inlined comments in multiline instructions preserved |
|
||||||
- continuous empty newlines honoured (albeit discouraged as of Docker CE 17.09) |
|
||||||
- `ARG` and `ENV` variable lookup and resolution |
|
||||||
|
|
||||||
Unsupported: |
|
||||||
- `\r` as a a line delimiter |
|
||||||
- only `\r\n` and `\n` are supported as being line delimiters |
|
||||||
- if a `\r` is detected the parser assumes that it is followed by a `\n` |
|
||||||
|
|
||||||
## Development Instructions |
|
||||||
|
|
||||||
If you wish to build and compile this project, you must first install [Node.js](https://nodejs.org/en/download/) if you have not already done so. |
|
||||||
After you have installed Node.js and cloned the repository with Git, you may now proceed to build and compile the project with the following commands: |
|
||||||
|
|
||||||
``` |
|
||||||
npm install |
|
||||||
npm run build |
|
||||||
npm test |
|
||||||
``` |
|
||||||
|
|
||||||
If you are planning to change the code, use `npm run watch` to get the |
|
||||||
TypeScript files transpiled on-the-fly as they are modified. |
|
||||||
|
|
||||||
## Installation Instructions |
|
||||||
|
|
||||||
To add this library as a dependency to your project, please add `dockerfile-ast` as a dependency in your package.json file. |
|
||||||
|
|
||||||
## Using this Module |
|
||||||
|
|
||||||
```TypeScript |
|
||||||
import { DockerfileParser } from 'dockerfile-ast'; |
|
||||||
|
|
||||||
const content = |
|
||||||
`FROM alpine |
|
||||||
ExposE 8080` |
|
||||||
|
|
||||||
let dockerfile = DockerfileParser.parse(content); |
|
||||||
let instructions = dockerfile.getInstructions(); |
|
||||||
for (let instruction of instructions) { |
|
||||||
// FROM |
|
||||||
// EXPOSE |
|
||||||
console.log(instruction.getKeyword()); |
|
||||||
// FROM |
|
||||||
// ExposE |
|
||||||
console.log(instruction.getInstruction()); |
|
||||||
} |
|
||||||
``` |
|
Binary file not shown.
@ -1,11 +0,0 @@ |
|||||||
import { Range, Position } from 'vscode-languageserver-types'; |
|
||||||
export declare class Argument { |
|
||||||
private readonly value; |
|
||||||
private readonly range; |
|
||||||
constructor(value: string, range: Range); |
|
||||||
toString(): string; |
|
||||||
getRange(): Range; |
|
||||||
getValue(): string; |
|
||||||
isAfter(position: Position): boolean; |
|
||||||
isBefore(position: Position): boolean; |
|
||||||
} |
|
@ -1,30 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
class Argument { |
|
||||||
constructor(value, range) { |
|
||||||
this.value = value; |
|
||||||
this.range = range; |
|
||||||
} |
|
||||||
toString() { |
|
||||||
return this.value; |
|
||||||
} |
|
||||||
getRange() { |
|
||||||
return this.range; |
|
||||||
} |
|
||||||
getValue() { |
|
||||||
return this.value; |
|
||||||
} |
|
||||||
isAfter(position) { |
|
||||||
if (this.range.end.line < position.line) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
return this.range.start.line > position.line ? true : this.range.start.character > position.character; |
|
||||||
} |
|
||||||
isBefore(position) { |
|
||||||
if (this.range.start.line < position.line) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
return this.range.end.line > position.line ? false : this.range.end.character < position.character; |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Argument = Argument; |
|
@ -1,19 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
import { Line } from './line'; |
|
||||||
export declare class Comment extends Line { |
|
||||||
constructor(document: TextDocument, range: Range); |
|
||||||
toString(): string; |
|
||||||
/** |
|
||||||
* Returns the content of this comment. This excludes leading and |
|
||||||
* trailing whitespace as well as the # symbol. If the comment only |
|
||||||
* consists of whitespace, the empty string will be returned. |
|
||||||
*/ |
|
||||||
getContent(): string; |
|
||||||
/** |
|
||||||
* Returns a range that includes the content of the comment |
|
||||||
* excluding any leading and trailing whitespace as well as the # |
|
||||||
* symbol. May return null if the comment only consists of whitespace |
|
||||||
* characters. |
|
||||||
*/ |
|
||||||
getContentRange(): Range | null; |
|
||||||
} |
|
@ -1,65 +0,0 @@ |
|||||||
"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_types_1 = require("vscode-languageserver-types"); |
|
||||||
const line_1 = require("./line"); |
|
||||||
const util_1 = require("./util"); |
|
||||||
class Comment extends line_1.Line { |
|
||||||
constructor(document, range) { |
|
||||||
super(document, range); |
|
||||||
} |
|
||||||
toString() { |
|
||||||
const content = this.getContent(); |
|
||||||
if (content) { |
|
||||||
return "# " + content; |
|
||||||
} |
|
||||||
return "#"; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Returns the content of this comment. This excludes leading and |
|
||||||
* trailing whitespace as well as the # symbol. If the comment only |
|
||||||
* consists of whitespace, the empty string will be returned. |
|
||||||
*/ |
|
||||||
getContent() { |
|
||||||
let range = this.getContentRange(); |
|
||||||
if (range === null) { |
|
||||||
return ""; |
|
||||||
} |
|
||||||
return this.document.getText().substring(this.document.offsetAt(range.start), this.document.offsetAt(range.end)); |
|
||||||
} |
|
||||||
/** |
|
||||||
* Returns a range that includes the content of the comment |
|
||||||
* excluding any leading and trailing whitespace as well as the # |
|
||||||
* symbol. May return null if the comment only consists of whitespace |
|
||||||
* characters. |
|
||||||
*/ |
|
||||||
getContentRange() { |
|
||||||
let range = this.getRange(); |
|
||||||
const startOffset = this.document.offsetAt(range.start); |
|
||||||
let raw = this.document.getText().substring(startOffset, this.document.offsetAt(range.end)); |
|
||||||
let start = -1; |
|
||||||
let end = -1; |
|
||||||
// skip the first # symbol
|
|
||||||
for (let i = 1; i < raw.length; i++) { |
|
||||||
if (!util_1.Util.isWhitespace(raw.charAt(i))) { |
|
||||||
start = i; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
if (start === -1) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
// go backwards up to the first # symbol
|
|
||||||
for (let i = raw.length - 1; i >= 1; i--) { |
|
||||||
if (!util_1.Util.isWhitespace(raw.charAt(i))) { |
|
||||||
end = i + 1; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
return vscode_languageserver_types_1.Range.create(this.document.positionAt(startOffset + start), this.document.positionAt(startOffset + end)); |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Comment = Comment; |
|
@ -1,33 +0,0 @@ |
|||||||
import { TextDocument, Range, Position } from 'vscode-languageserver-types'; |
|
||||||
import * as ast from './main'; |
|
||||||
import { ParserDirective } from './parserDirective'; |
|
||||||
import { ImageTemplate } from './imageTemplate'; |
|
||||||
import { Instruction } from './instruction'; |
|
||||||
import { Arg } from './instructions/arg'; |
|
||||||
export declare class Dockerfile extends ImageTemplate implements ast.Dockerfile { |
|
||||||
private readonly document; |
|
||||||
private readonly initialInstructions; |
|
||||||
private readonly buildStages; |
|
||||||
private currentBuildStage; |
|
||||||
private directives; |
|
||||||
/** |
|
||||||
* Whether a FROM instruction has been added to this Dockerfile or not. |
|
||||||
*/ |
|
||||||
private foundFrom; |
|
||||||
constructor(document: TextDocument); |
|
||||||
getEscapeCharacter(): string; |
|
||||||
getInitialARGs(): Arg[]; |
|
||||||
getContainingImage(position: Position): ImageTemplate | null; |
|
||||||
addInstruction(instruction: Instruction): void; |
|
||||||
setDirectives(directives: ParserDirective[]): void; |
|
||||||
getDirective(): ParserDirective | null; |
|
||||||
getDirectives(): ParserDirective[]; |
|
||||||
resolveVariable(variable: string, line: number): string | null | undefined; |
|
||||||
getAvailableVariables(currentLine: number): string[]; |
|
||||||
/** |
|
||||||
* Internally reorganize the comments in the Dockerfile and allocate |
|
||||||
* them to the relevant build stages that they belong to. |
|
||||||
*/ |
|
||||||
organizeComments(): void; |
|
||||||
getRange(): Range | null; |
|
||||||
} |
|
@ -1,183 +0,0 @@ |
|||||||
/* -------------------------------------------------------------------------------------------- |
|
||||||
* 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 }); |
|
||||||
const vscode_languageserver_types_1 = require("vscode-languageserver-types"); |
|
||||||
const ast = require("./main"); |
|
||||||
const imageTemplate_1 = require("./imageTemplate"); |
|
||||||
const from_1 = require("./instructions/from"); |
|
||||||
const util_1 = require("./util"); |
|
||||||
const main_1 = require("./main"); |
|
||||||
class Dockerfile extends imageTemplate_1.ImageTemplate { |
|
||||||
constructor(document) { |
|
||||||
super(); |
|
||||||
this.initialInstructions = new imageTemplate_1.ImageTemplate(); |
|
||||||
this.buildStages = []; |
|
||||||
this.directives = []; |
|
||||||
/** |
|
||||||
* Whether a FROM instruction has been added to this Dockerfile or not. |
|
||||||
*/ |
|
||||||
this.foundFrom = false; |
|
||||||
this.document = document; |
|
||||||
} |
|
||||||
getEscapeCharacter() { |
|
||||||
for (const directive of this.directives) { |
|
||||||
if (directive.getDirective() === ast.Directive.escape) { |
|
||||||
const value = directive.getValue(); |
|
||||||
if (value === '\\' || value === '`') { |
|
||||||
return value; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return '\\'; |
|
||||||
} |
|
||||||
getInitialARGs() { |
|
||||||
return this.initialInstructions.getARGs(); |
|
||||||
} |
|
||||||
getContainingImage(position) { |
|
||||||
let range = vscode_languageserver_types_1.Range.create(vscode_languageserver_types_1.Position.create(0, 0), this.document.positionAt(this.document.getText().length)); |
|
||||||
if (!util_1.Util.isInsideRange(position, range)) { |
|
||||||
// not inside the document, invalid position
|
|
||||||
return null; |
|
||||||
} |
|
||||||
if (this.initialInstructions.getComments().length > 0 || this.initialInstructions.getInstructions().length > 0) { |
|
||||||
if (util_1.Util.isInsideRange(position, this.initialInstructions.getRange())) { |
|
||||||
return this.initialInstructions; |
|
||||||
} |
|
||||||
} |
|
||||||
for (const buildStage of this.buildStages) { |
|
||||||
if (util_1.Util.isInsideRange(position, buildStage.getRange())) { |
|
||||||
return buildStage; |
|
||||||
} |
|
||||||
} |
|
||||||
return this; |
|
||||||
} |
|
||||||
addInstruction(instruction) { |
|
||||||
if (instruction.getKeyword() === main_1.Keyword.FROM) { |
|
||||||
this.currentBuildStage = new imageTemplate_1.ImageTemplate(); |
|
||||||
this.buildStages.push(this.currentBuildStage); |
|
||||||
this.foundFrom = true; |
|
||||||
} |
|
||||||
else if (!this.foundFrom) { |
|
||||||
this.initialInstructions.addInstruction(instruction); |
|
||||||
} |
|
||||||
if (this.foundFrom) { |
|
||||||
this.currentBuildStage.addInstruction(instruction); |
|
||||||
} |
|
||||||
super.addInstruction(instruction); |
|
||||||
} |
|
||||||
setDirectives(directives) { |
|
||||||
this.directives = directives; |
|
||||||
} |
|
||||||
getDirective() { |
|
||||||
return this.directives.length === 0 ? null : this.directives[0]; |
|
||||||
} |
|
||||||
getDirectives() { |
|
||||||
return this.directives; |
|
||||||
} |
|
||||||
resolveVariable(variable, line) { |
|
||||||
for (let from of this.getFROMs()) { |
|
||||||
let range = from.getRange(); |
|
||||||
if (range.start.line <= line && line <= range.end.line) { |
|
||||||
// resolve the FROM variable against the initial ARGs
|
|
||||||
let initialARGs = new imageTemplate_1.ImageTemplate(); |
|
||||||
for (let instruction of this.initialInstructions.getARGs()) { |
|
||||||
initialARGs.addInstruction(instruction); |
|
||||||
} |
|
||||||
return initialARGs.resolveVariable(variable, line); |
|
||||||
} |
|
||||||
} |
|
||||||
let image = this.getContainingImage(vscode_languageserver_types_1.Position.create(line, 0)); |
|
||||||
if (image === null) { |
|
||||||
return undefined; |
|
||||||
} |
|
||||||
let resolvedVariable = image.resolveVariable(variable, line); |
|
||||||
if (resolvedVariable === null) { |
|
||||||
// refers to an uninitialized ARG variable,
|
|
||||||
// try resolving it against the initial ARGs then
|
|
||||||
let initialARGs = new imageTemplate_1.ImageTemplate(); |
|
||||||
for (let instruction of this.initialInstructions.getARGs()) { |
|
||||||
initialARGs.addInstruction(instruction); |
|
||||||
} |
|
||||||
return initialARGs.resolveVariable(variable, line); |
|
||||||
} |
|
||||||
return resolvedVariable; |
|
||||||
} |
|
||||||
getAvailableVariables(currentLine) { |
|
||||||
if (this.getInstructionAt(currentLine) instanceof from_1.From) { |
|
||||||
let variables = []; |
|
||||||
for (let arg of this.getInitialARGs()) { |
|
||||||
let property = arg.getProperty(); |
|
||||||
if (property) { |
|
||||||
variables.push(property.getName()); |
|
||||||
} |
|
||||||
} |
|
||||||
return variables; |
|
||||||
} |
|
||||||
let image = this.getContainingImage(vscode_languageserver_types_1.Position.create(currentLine, 0)); |
|
||||||
return image ? image.getAvailableVariables(currentLine) : []; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Internally reorganize the comments in the Dockerfile and allocate |
|
||||||
* them to the relevant build stages that they belong to. |
|
||||||
*/ |
|
||||||
organizeComments() { |
|
||||||
const comments = this.getComments(); |
|
||||||
for (let i = 0; i < comments.length; i++) { |
|
||||||
if (util_1.Util.isInsideRange(comments[i].getRange().end, this.initialInstructions.getRange())) { |
|
||||||
this.initialInstructions.addComment(comments[i]); |
|
||||||
} |
|
||||||
else { |
|
||||||
for (const buildStage of this.buildStages) { |
|
||||||
if (util_1.Util.isInsideRange(comments[i].getRange().start, buildStage.getRange())) { |
|
||||||
buildStage.addComment(comments[i]); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
getRange() { |
|
||||||
const comments = this.getComments(); |
|
||||||
const instructions = this.getInstructions(); |
|
||||||
let range = null; |
|
||||||
if (comments.length === 0) { |
|
||||||
if (instructions.length > 0) { |
|
||||||
range = vscode_languageserver_types_1.Range.create(instructions[0].getRange().start, instructions[instructions.length - 1].getRange().end); |
|
||||||
} |
|
||||||
} |
|
||||||
else if (instructions.length === 0) { |
|
||||||
range = vscode_languageserver_types_1.Range.create(comments[0].getRange().start, comments[comments.length - 1].getRange().end); |
|
||||||
} |
|
||||||
else { |
|
||||||
const commentStart = comments[0].getRange().start; |
|
||||||
const commentEnd = comments[comments.length - 1].getRange().end; |
|
||||||
const instructionStart = instructions[0].getRange().start; |
|
||||||
const instructionEnd = instructions[instructions.length - 1].getRange().end; |
|
||||||
if (commentStart.line < instructionStart.line) { |
|
||||||
if (commentEnd.line < instructionEnd.line) { |
|
||||||
range = vscode_languageserver_types_1.Range.create(commentStart, instructionEnd); |
|
||||||
} |
|
||||||
range = vscode_languageserver_types_1.Range.create(commentStart, commentEnd); |
|
||||||
} |
|
||||||
else if (commentEnd.line < instructionEnd.line) { |
|
||||||
range = vscode_languageserver_types_1.Range.create(instructionStart, instructionEnd); |
|
||||||
} |
|
||||||
else { |
|
||||||
range = vscode_languageserver_types_1.Range.create(instructionStart, commentEnd); |
|
||||||
} |
|
||||||
} |
|
||||||
if (range === null) { |
|
||||||
if (this.directives.length === 0) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
return this.directives[0].getRange(); |
|
||||||
} |
|
||||||
else if (this.directives.length === 0) { |
|
||||||
return range; |
|
||||||
} |
|
||||||
return vscode_languageserver_types_1.Range.create(this.directives[0].getRange().start, range.end); |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Dockerfile = Dockerfile; |
|
@ -1,55 +0,0 @@ |
|||||||
import { Range, TextDocument } from 'vscode-languageserver-types'; |
|
||||||
import { FlagOption } from './flagOption'; |
|
||||||
export declare class Flag { |
|
||||||
private readonly range; |
|
||||||
private readonly name; |
|
||||||
private readonly nameRange; |
|
||||||
private readonly value; |
|
||||||
private readonly valueRange; |
|
||||||
private readonly options; |
|
||||||
constructor(document: TextDocument, range: Range, name: string, nameRange: Range, value: string | null, valueRange: Range | null); |
|
||||||
private createFlagOption; |
|
||||||
toString(): string; |
|
||||||
/** |
|
||||||
* Returns the range that encompasses this entire flag. This includes the |
|
||||||
* -- prefix in the beginning to the last character of the flag's value (if |
|
||||||
* it has been defined). |
|
||||||
* |
|
||||||
* @return the entire range of this flag |
|
||||||
*/ |
|
||||||
getRange(): Range; |
|
||||||
/** |
|
||||||
* Returns the name of this flag. The name does not include the -- prefix. |
|
||||||
* Thus, for HEALTHCHECK's --interval flag, interval is the flag's name and |
|
||||||
* not --interval. |
|
||||||
* |
|
||||||
* @return this flag's name |
|
||||||
*/ |
|
||||||
getName(): string; |
|
||||||
/** |
|
||||||
* Returns the range that encompasses the flag's name |
|
||||||
* |
|
||||||
* @return the range containing the flag's name |
|
||||||
*/ |
|
||||||
getNameRange(): Range; |
|
||||||
/** |
|
||||||
* Returns the value that has been set to this flag. May be null if the |
|
||||||
* flag is invalid and has no value set like a --start-period. If the flag |
|
||||||
* is instead a --start-period= with an equals sign then the flag's value |
|
||||||
* is the empty string. |
|
||||||
* |
|
||||||
* @return this flag's value if it has been defined, null otherwise |
|
||||||
*/ |
|
||||||
getValue(): string | null; |
|
||||||
/** |
|
||||||
* Returns the range that encompasses this flag's value. If no value has |
|
||||||
* been set then null will be returned. |
|
||||||
* |
|
||||||
* @return the range containing this flag's value, or null if the flag |
|
||||||
* has no value defined |
|
||||||
*/ |
|
||||||
getValueRange(): Range | null; |
|
||||||
getOption(name: string): FlagOption | null; |
|
||||||
getOptions(): FlagOption[]; |
|
||||||
hasOptions(): boolean; |
|
||||||
} |
|
@ -1,125 +0,0 @@ |
|||||||
"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_types_1 = require("vscode-languageserver-types"); |
|
||||||
const flagOption_1 = require("./flagOption"); |
|
||||||
class Flag { |
|
||||||
constructor(document, range, name, nameRange, value, valueRange) { |
|
||||||
this.options = []; |
|
||||||
this.range = range; |
|
||||||
this.name = name; |
|
||||||
this.nameRange = nameRange; |
|
||||||
this.value = value; |
|
||||||
this.valueRange = valueRange; |
|
||||||
if (this.value !== null) { |
|
||||||
let offset = document.offsetAt(valueRange.start); |
|
||||||
let nameStart = -1; |
|
||||||
let valueStart = -1; |
|
||||||
let hasOptions = false; |
|
||||||
for (let i = 0; i < value.length; i++) { |
|
||||||
switch (value.charAt(i)) { |
|
||||||
case '=': |
|
||||||
hasOptions = true; |
|
||||||
if (valueStart === -1) { |
|
||||||
valueStart = i + 1; |
|
||||||
break; |
|
||||||
} |
|
||||||
break; |
|
||||||
case ',': |
|
||||||
this.options.push(this.createFlagOption(document, value, offset, nameStart, valueStart, i)); |
|
||||||
nameStart = -1; |
|
||||||
valueStart = -1; |
|
||||||
break; |
|
||||||
default: |
|
||||||
if (nameStart === -1) { |
|
||||||
nameStart = i; |
|
||||||
} |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
if (hasOptions && nameStart !== -1) { |
|
||||||
this.options.push(this.createFlagOption(document, value, offset, nameStart, valueStart, value.length)); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
createFlagOption(document, content, documentOffset, nameStart, valueStart, valueEnd) { |
|
||||||
const optionRange = vscode_languageserver_types_1.Range.create(document.positionAt(documentOffset + nameStart), document.positionAt(documentOffset + valueEnd)); |
|
||||||
if (valueStart === -1) { |
|
||||||
return new flagOption_1.FlagOption(optionRange, content.substring(nameStart, valueEnd), optionRange, null, null); |
|
||||||
} |
|
||||||
return new flagOption_1.FlagOption(optionRange, content.substring(nameStart, valueStart - 1), vscode_languageserver_types_1.Range.create(document.positionAt(documentOffset + nameStart), document.positionAt(documentOffset + valueStart - 1)), content.substring(valueStart, valueEnd), vscode_languageserver_types_1.Range.create(document.positionAt(documentOffset + valueStart), document.positionAt(documentOffset + valueEnd))); |
|
||||||
} |
|
||||||
toString() { |
|
||||||
if (this.valueRange) { |
|
||||||
return "--" + this.name + "=" + this.value; |
|
||||||
} |
|
||||||
return "--" + this.name; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Returns the range that encompasses this entire flag. This includes the |
|
||||||
* -- prefix in the beginning to the last character of the flag's value (if |
|
||||||
* it has been defined). |
|
||||||
* |
|
||||||
* @return the entire range of this flag |
|
||||||
*/ |
|
||||||
getRange() { |
|
||||||
return this.range; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Returns the name of this flag. The name does not include the -- prefix. |
|
||||||
* Thus, for HEALTHCHECK's --interval flag, interval is the flag's name and |
|
||||||
* not --interval. |
|
||||||
* |
|
||||||
* @return this flag's name |
|
||||||
*/ |
|
||||||
getName() { |
|
||||||
return this.name; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Returns the range that encompasses the flag's name |
|
||||||
* |
|
||||||
* @return the range containing the flag's name |
|
||||||
*/ |
|
||||||
getNameRange() { |
|
||||||
return this.nameRange; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Returns the value that has been set to this flag. May be null if the |
|
||||||
* flag is invalid and has no value set like a --start-period. If the flag |
|
||||||
* is instead a --start-period= with an equals sign then the flag's value |
|
||||||
* is the empty string. |
|
||||||
* |
|
||||||
* @return this flag's value if it has been defined, null otherwise |
|
||||||
*/ |
|
||||||
getValue() { |
|
||||||
return this.value; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Returns the range that encompasses this flag's value. If no value has |
|
||||||
* been set then null will be returned. |
|
||||||
* |
|
||||||
* @return the range containing this flag's value, or null if the flag |
|
||||||
* has no value defined |
|
||||||
*/ |
|
||||||
getValueRange() { |
|
||||||
return this.valueRange; |
|
||||||
} |
|
||||||
getOption(name) { |
|
||||||
for (const option of this.options) { |
|
||||||
if (option.getName() === name) { |
|
||||||
return option; |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
getOptions() { |
|
||||||
return this.options; |
|
||||||
} |
|
||||||
hasOptions() { |
|
||||||
return this.options.length > 0; |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Flag = Flag; |
|
@ -1,15 +0,0 @@ |
|||||||
import { Range } from 'vscode-languageserver-types'; |
|
||||||
export declare class FlagOption { |
|
||||||
private readonly range; |
|
||||||
private readonly name; |
|
||||||
private readonly nameRange; |
|
||||||
private readonly value; |
|
||||||
private readonly valueRange; |
|
||||||
constructor(range: Range, name: string, nameRange: Range, value: string | null, valueRange: Range | null); |
|
||||||
toString(): string; |
|
||||||
getRange(): Range; |
|
||||||
getName(): string; |
|
||||||
getNameRange(): Range; |
|
||||||
getValue(): string | null; |
|
||||||
getValueRange(): Range | null; |
|
||||||
} |
|
@ -1,33 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
class FlagOption { |
|
||||||
constructor(range, name, nameRange, value, valueRange) { |
|
||||||
this.range = range; |
|
||||||
this.name = name; |
|
||||||
this.nameRange = nameRange; |
|
||||||
this.value = value; |
|
||||||
this.valueRange = valueRange; |
|
||||||
} |
|
||||||
toString() { |
|
||||||
if (this.valueRange !== null) { |
|
||||||
return this.name + "=" + this.value; |
|
||||||
} |
|
||||||
return this.name; |
|
||||||
} |
|
||||||
getRange() { |
|
||||||
return this.range; |
|
||||||
} |
|
||||||
getName() { |
|
||||||
return this.name; |
|
||||||
} |
|
||||||
getNameRange() { |
|
||||||
return this.nameRange; |
|
||||||
} |
|
||||||
getValue() { |
|
||||||
return this.value; |
|
||||||
} |
|
||||||
getValueRange() { |
|
||||||
return this.valueRange; |
|
||||||
} |
|
||||||
} |
|
||||||
exports.FlagOption = FlagOption; |
|
@ -1,67 +0,0 @@ |
|||||||
import { Range, Position } from 'vscode-languageserver-types'; |
|
||||||
import * as ast from './main'; |
|
||||||
import { Comment } from './comment'; |
|
||||||
import { Instruction } from './instruction'; |
|
||||||
import { Arg } from './instructions/arg'; |
|
||||||
import { Cmd } from './instructions/cmd'; |
|
||||||
import { Copy } from './instructions/copy'; |
|
||||||
import { Env } from './instructions/env'; |
|
||||||
import { Entrypoint } from './instructions/entrypoint'; |
|
||||||
import { From } from './instructions/from'; |
|
||||||
import { Healthcheck } from './instructions/healthcheck'; |
|
||||||
export declare class ImageTemplate implements ast.ImageTemplate { |
|
||||||
private readonly comments; |
|
||||||
private readonly instructions; |
|
||||||
addComment(comment: Comment): void; |
|
||||||
getComments(): Comment[]; |
|
||||||
addInstruction(instruction: Instruction): void; |
|
||||||
getInstructions(): Instruction[]; |
|
||||||
protected getInstructionAt(line: number): Instruction | null; |
|
||||||
/** |
|
||||||
* Gets all the ARG instructions that are defined in this image. |
|
||||||
*/ |
|
||||||
getARGs(): Arg[]; |
|
||||||
/** |
|
||||||
* Gets all the CMD instructions that are defined in this image. |
|
||||||
*/ |
|
||||||
getCMDs(): Cmd[]; |
|
||||||
/** |
|
||||||
* Gets all the COPY instructions that are defined in this image. |
|
||||||
*/ |
|
||||||
getCOPYs(): Copy[]; |
|
||||||
/** |
|
||||||
* Gets all the ENTRYPOINT instructions that are defined in this image. |
|
||||||
*/ |
|
||||||
getENTRYPOINTs(): Entrypoint[]; |
|
||||||
/** |
|
||||||
* Gets all the ENV instructions that are defined in this image. |
|
||||||
*/ |
|
||||||
getENVs(): Env[]; |
|
||||||
/** |
|
||||||
* Gets all the FROM instructions that are defined in this image. |
|
||||||
*/ |
|
||||||
getFROMs(): From[]; |
|
||||||
/** |
|
||||||
* Gets all the HEALTHCHECK instructions that are defined in this image. |
|
||||||
*/ |
|
||||||
getHEALTHCHECKs(): Healthcheck[]; |
|
||||||
getOnbuildTriggers(): Instruction[]; |
|
||||||
getAvailableVariables(currentLine: number): string[]; |
|
||||||
/** |
|
||||||
* Resolves a variable with the given name at the specified line |
|
||||||
* to its value. If null is returned, then the variable has been |
|
||||||
* defined but no value was given. If undefined is returned, then |
|
||||||
* a variable with the given name has not been defined yet as of |
|
||||||
* the given line. |
|
||||||
* |
|
||||||
* @param variable the name of the variable to resolve |
|
||||||
* @param line the line number that the variable is on, zero-based |
|
||||||
* @return the value of the variable as defined by an ARG or ENV |
|
||||||
* instruction, or null if no value has been specified, or |
|
||||||
* undefined if a variable with the given name has not |
|
||||||
* been defined |
|
||||||
*/ |
|
||||||
resolveVariable(variable: string, line: number): string | null | undefined; |
|
||||||
getRange(): Range | null; |
|
||||||
contains(position: Position): boolean; |
|
||||||
} |
|
@ -1,218 +0,0 @@ |
|||||||
/* -------------------------------------------------------------------------------------------- |
|
||||||
* 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 }); |
|
||||||
const vscode_languageserver_types_1 = require("vscode-languageserver-types"); |
|
||||||
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 util_1 = require("./util"); |
|
||||||
class ImageTemplate { |
|
||||||
constructor() { |
|
||||||
this.comments = []; |
|
||||||
this.instructions = []; |
|
||||||
} |
|
||||||
addComment(comment) { |
|
||||||
this.comments.push(comment); |
|
||||||
} |
|
||||||
getComments() { |
|
||||||
return this.comments; |
|
||||||
} |
|
||||||
addInstruction(instruction) { |
|
||||||
this.instructions.push(instruction); |
|
||||||
} |
|
||||||
getInstructions() { |
|
||||||
return this.instructions; |
|
||||||
} |
|
||||||
getInstructionAt(line) { |
|
||||||
for (let instruction of this.instructions) { |
|
||||||
if (util_1.Util.isInsideRange(vscode_languageserver_types_1.Position.create(line, 0), instruction.getRange())) { |
|
||||||
return instruction; |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Gets all the ARG instructions that are defined in this image. |
|
||||||
*/ |
|
||||||
getARGs() { |
|
||||||
let args = []; |
|
||||||
for (let instruction of this.instructions) { |
|
||||||
if (instruction instanceof arg_1.Arg) { |
|
||||||
args.push(instruction); |
|
||||||
} |
|
||||||
} |
|
||||||
return args; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Gets all the CMD instructions that are defined in this image. |
|
||||||
*/ |
|
||||||
getCMDs() { |
|
||||||
let cmds = []; |
|
||||||
for (let instruction of this.instructions) { |
|
||||||
if (instruction instanceof cmd_1.Cmd) { |
|
||||||
cmds.push(instruction); |
|
||||||
} |
|
||||||
} |
|
||||||
return cmds; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Gets all the COPY instructions that are defined in this image. |
|
||||||
*/ |
|
||||||
getCOPYs() { |
|
||||||
let copies = []; |
|
||||||
for (let instruction of this.instructions) { |
|
||||||
if (instruction instanceof copy_1.Copy) { |
|
||||||
copies.push(instruction); |
|
||||||
} |
|
||||||
} |
|
||||||
return copies; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Gets all the ENTRYPOINT instructions that are defined in this image. |
|
||||||
*/ |
|
||||||
getENTRYPOINTs() { |
|
||||||
let froms = []; |
|
||||||
for (let instruction of this.instructions) { |
|
||||||
if (instruction instanceof entrypoint_1.Entrypoint) { |
|
||||||
froms.push(instruction); |
|
||||||
} |
|
||||||
} |
|
||||||
return froms; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Gets all the ENV instructions that are defined in this image. |
|
||||||
*/ |
|
||||||
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 image. |
|
||||||
*/ |
|
||||||
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 image. |
|
||||||
*/ |
|
||||||
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; |
|
||||||
} |
|
||||||
getAvailableVariables(currentLine) { |
|
||||||
const variables = []; |
|
||||||
for (const arg of this.getARGs()) { |
|
||||||
if (arg.isBefore(currentLine)) { |
|
||||||
const property = arg.getProperty(); |
|
||||||
if (property) { |
|
||||||
const variable = property.getName(); |
|
||||||
if (variables.indexOf(variable) === -1) { |
|
||||||
variables.push(variable); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
for (const env of this.getENVs()) { |
|
||||||
if (env.isBefore(currentLine)) { |
|
||||||
for (const property of env.getProperties()) { |
|
||||||
const variable = property.getName(); |
|
||||||
if (variables.indexOf(variable) === -1) { |
|
||||||
variables.push(variable); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return variables; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Resolves a variable with the given name at the specified line |
|
||||||
* to its value. If null is returned, then the variable has been |
|
||||||
* defined but no value was given. If undefined is returned, then |
|
||||||
* a variable with the given name has not been defined yet as of |
|
||||||
* the given line. |
|
||||||
* |
|
||||||
* @param variable the name of the variable to resolve |
|
||||||
* @param line the line number that the variable is on, zero-based |
|
||||||
* @return the value of the variable as defined by an ARG or ENV |
|
||||||
* instruction, or null if no value has been specified, or |
|
||||||
* undefined if a variable with the given name has not |
|
||||||
* been defined |
|
||||||
*/ |
|
||||||
resolveVariable(variable, line) { |
|
||||||
let envs = this.getENVs(); |
|
||||||
for (let i = envs.length - 1; i >= 0; i--) { |
|
||||||
if (envs[i].isBefore(line)) { |
|
||||||
for (let property of envs[i].getProperties()) { |
|
||||||
if (property.getName() === variable) { |
|
||||||
return property.getValue(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
let args = this.getARGs(); |
|
||||||
for (let i = args.length - 1; i >= 0; i--) { |
|
||||||
if (args[i].isBefore(line)) { |
|
||||||
let property = args[i].getProperty(); |
|
||||||
if (property && property.getName() === variable) { |
|
||||||
return property.getValue(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return undefined; |
|
||||||
} |
|
||||||
getRange() { |
|
||||||
const instructions = this.getInstructions(); |
|
||||||
if (instructions.length === 0) { |
|
||||||
// all templates should have instructions, this only happens for
|
|
||||||
// the initial set of instruction
|
|
||||||
return vscode_languageserver_types_1.Range.create(0, 0, 0, 0); |
|
||||||
} |
|
||||||
const instructionStart = instructions[0].getRange().start; |
|
||||||
const instructionEnd = instructions[instructions.length - 1].getRange().end; |
|
||||||
return vscode_languageserver_types_1.Range.create(instructionStart, instructionEnd); |
|
||||||
} |
|
||||||
contains(position) { |
|
||||||
const range = this.getRange(); |
|
||||||
if (range === null) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
return util_1.Util.isInsideRange(position, range); |
|
||||||
} |
|
||||||
} |
|
||||||
exports.ImageTemplate = ImageTemplate; |
|
@ -1,27 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
import { Dockerfile } from './dockerfile'; |
|
||||||
import { Line } from './line'; |
|
||||||
import { Argument } from './argument'; |
|
||||||
import { Variable } from './variable'; |
|
||||||
export declare class Instruction extends Line { |
|
||||||
protected readonly dockerfile: Dockerfile; |
|
||||||
protected readonly escapeChar: string; |
|
||||||
private readonly instruction; |
|
||||||
private readonly instructionRange; |
|
||||||
constructor(document: TextDocument, range: Range, dockerfile: Dockerfile, escapeChar: string, instruction: string, instructionRange: Range); |
|
||||||
toString(): string; |
|
||||||
protected getRangeContent(range: Range | null): string | null; |
|
||||||
getInstructionRange(): Range; |
|
||||||
getInstruction(): string; |
|
||||||
getKeyword(): string; |
|
||||||
getArgumentsRange(): Range | null; |
|
||||||
getArgumentsRanges(): Range[]; |
|
||||||
getRawArgumentsContent(): string | null; |
|
||||||
getArgumentsContent(): string | null; |
|
||||||
getArguments(): Argument[]; |
|
||||||
private getRawArguments; |
|
||||||
getExpandedArguments(): Argument[]; |
|
||||||
getVariables(): Variable[]; |
|
||||||
private parseVariables; |
|
||||||
private isBuildVariable; |
|
||||||
} |
|
@ -1,586 +0,0 @@ |
|||||||
"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_types_1 = require("vscode-languageserver-types"); |
|
||||||
const util_1 = require("./util"); |
|
||||||
const line_1 = require("./line"); |
|
||||||
const argument_1 = require("./argument"); |
|
||||||
const variable_1 = require("./variable"); |
|
||||||
const main_1 = require("./main"); |
|
||||||
class Instruction extends line_1.Line { |
|
||||||
constructor(document, range, dockerfile, escapeChar, instruction, instructionRange) { |
|
||||||
super(document, range); |
|
||||||
this.dockerfile = dockerfile; |
|
||||||
this.escapeChar = escapeChar; |
|
||||||
this.instruction = instruction; |
|
||||||
this.instructionRange = instructionRange; |
|
||||||
} |
|
||||||
toString() { |
|
||||||
let value = this.getKeyword(); |
|
||||||
for (let arg of this.getRawArguments()) { |
|
||||||
value += ' '; |
|
||||||
value += arg.getValue(); |
|
||||||
} |
|
||||||
return value; |
|
||||||
} |
|
||||||
getRangeContent(range) { |
|
||||||
if (range === null) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
return this.document.getText().substring(this.document.offsetAt(range.start), this.document.offsetAt(range.end)); |
|
||||||
} |
|
||||||
getInstructionRange() { |
|
||||||
return this.instructionRange; |
|
||||||
} |
|
||||||
getInstruction() { |
|
||||||
return this.instruction; |
|
||||||
} |
|
||||||
getKeyword() { |
|
||||||
return this.getInstruction().toUpperCase(); |
|
||||||
} |
|
||||||
getArgumentsRange() { |
|
||||||
let args = this.getArguments(); |
|
||||||
if (args.length === 0) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
return vscode_languageserver_types_1.Range.create(args[0].getRange().start, args[args.length - 1].getRange().end); |
|
||||||
} |
|
||||||
getArgumentsRanges() { |
|
||||||
let args = this.getArguments(); |
|
||||||
if (args.length === 0) { |
|
||||||
return []; |
|
||||||
} |
|
||||||
if (args[0].getRange().start.line === args[args.length - 1].getRange().end.line) { |
|
||||||
return [vscode_languageserver_types_1.Range.create(args[0].getRange().start, args[args.length - 1].getRange().end)]; |
|
||||||
} |
|
||||||
let ranges = []; |
|
||||||
let end = -1; |
|
||||||
let startPosition = args[0].getRange().start; |
|
||||||
let range = this.getInstructionRange(); |
|
||||||
let extra = this.document.offsetAt(startPosition) - this.document.offsetAt(range.start); |
|
||||||
let content = this.getTextContent(); |
|
||||||
let fullArgs = content.substring(extra, this.document.offsetAt(args[args.length - 1].getRange().end) - this.document.offsetAt(range.start)); |
|
||||||
let offset = this.document.offsetAt(range.start) + extra; |
|
||||||
let start = false; |
|
||||||
let comment = false; |
|
||||||
for (let i = 0; i < fullArgs.length; i++) { |
|
||||||
let char = fullArgs.charAt(i); |
|
||||||
if (char === this.escapeChar) { |
|
||||||
let next = fullArgs.charAt(i + 1); |
|
||||||
if (next === ' ' || next === '\t') { |
|
||||||
whitespaceCheck: for (let j = i + 2; j < fullArgs.length; j++) { |
|
||||||
switch (fullArgs.charAt(j)) { |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
continue; |
|
||||||
case '\r': |
|
||||||
j++; |
|
||||||
case '\n': |
|
||||||
if (startPosition !== null) { |
|
||||||
ranges.push(vscode_languageserver_types_1.Range.create(startPosition, this.document.positionAt(offset + end + 1))); |
|
||||||
} |
|
||||||
startPosition = null; |
|
||||||
start = true; |
|
||||||
comment = false; |
|
||||||
i = j; |
|
||||||
break whitespaceCheck; |
|
||||||
default: |
|
||||||
break whitespaceCheck; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
else if (next === '\r') { |
|
||||||
if (startPosition !== null) { |
|
||||||
ranges.push(vscode_languageserver_types_1.Range.create(startPosition, this.document.positionAt(offset + end + 1))); |
|
||||||
startPosition = null; |
|
||||||
} |
|
||||||
start = true; |
|
||||||
comment = false; |
|
||||||
i += 2; |
|
||||||
} |
|
||||||
else if (next === '\n') { |
|
||||||
if (startPosition !== null) { |
|
||||||
ranges.push(vscode_languageserver_types_1.Range.create(startPosition, this.document.positionAt(offset + end + 1))); |
|
||||||
} |
|
||||||
startPosition = null; |
|
||||||
start = true; |
|
||||||
comment = false; |
|
||||||
i++; |
|
||||||
} |
|
||||||
else { |
|
||||||
i++; |
|
||||||
} |
|
||||||
} |
|
||||||
else if (util_1.Util.isNewline(char)) { |
|
||||||
if (comment) { |
|
||||||
startPosition = null; |
|
||||||
start = true; |
|
||||||
comment = false; |
|
||||||
} |
|
||||||
} |
|
||||||
else { |
|
||||||
if (!comment) { |
|
||||||
if (startPosition === null) { |
|
||||||
if (char === '#') { |
|
||||||
comment = true; |
|
||||||
continue; |
|
||||||
} |
|
||||||
let position = this.document.positionAt(offset + i); |
|
||||||
if (position.character !== 0) { |
|
||||||
startPosition = vscode_languageserver_types_1.Position.create(position.line, 0); |
|
||||||
} |
|
||||||
} |
|
||||||
end = i; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
if (startPosition === null) { |
|
||||||
// should only happen if the last argument is on its own line with
|
|
||||||
// no leading whitespace
|
|
||||||
ranges.push(vscode_languageserver_types_1.Range.create(this.document.positionAt(offset + end), this.document.positionAt(offset + end + 1))); |
|
||||||
} |
|
||||||
else { |
|
||||||
ranges.push(vscode_languageserver_types_1.Range.create(startPosition, this.document.positionAt(offset + end + 1))); |
|
||||||
} |
|
||||||
return ranges; |
|
||||||
} |
|
||||||
getRawArgumentsContent() { |
|
||||||
let args = this.getArguments(); |
|
||||||
if (args.length === 0) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
return this.getRangeContent(vscode_languageserver_types_1.Range.create(args[0].getRange().start, args[args.length - 1].getRange().end)); |
|
||||||
} |
|
||||||
getArgumentsContent() { |
|
||||||
let args = this.getArguments(); |
|
||||||
if (args.length === 0) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
let content = ""; |
|
||||||
let ranges = this.getArgumentsRanges(); |
|
||||||
let documentText = this.document.getText(); |
|
||||||
for (let range of ranges) { |
|
||||||
content += documentText.substring(this.document.offsetAt(range.start), this.document.offsetAt(range.end)); |
|
||||||
} |
|
||||||
return content; |
|
||||||
} |
|
||||||
getArguments() { |
|
||||||
return this.getRawArguments(); |
|
||||||
} |
|
||||||
getRawArguments() { |
|
||||||
let args = []; |
|
||||||
let range = this.getInstructionRange(); |
|
||||||
let extra = this.document.offsetAt(range.end) - this.document.offsetAt(range.start); |
|
||||||
let content = this.getTextContent(); |
|
||||||
let fullArgs = content.substring(extra); |
|
||||||
let offset = this.document.offsetAt(range.start) + extra; |
|
||||||
let start = false; |
|
||||||
let comment = false; |
|
||||||
let found = -1; |
|
||||||
// determines whether the parser has found a space or tab
|
|
||||||
// whitespace character that's a part of an escaped newline sequence
|
|
||||||
let escapedWhitespaceDetected = false; |
|
||||||
// determines if the parser is currently in an escaped newline sequence
|
|
||||||
let escaping = false; |
|
||||||
let escapeMarker = -1; |
|
||||||
let escapedArg = ""; |
|
||||||
for (let i = 0; i < fullArgs.length; i++) { |
|
||||||
let char = fullArgs.charAt(i); |
|
||||||
if (util_1.Util.isWhitespace(char)) { |
|
||||||
if (escaping) { |
|
||||||
escapedWhitespaceDetected = true; |
|
||||||
if (util_1.Util.isNewline(char)) { |
|
||||||
// reached a newline, any previously
|
|
||||||
// detected whitespace should be ignored
|
|
||||||
escapedWhitespaceDetected = false; |
|
||||||
if (comment) { |
|
||||||
// reached a newline, no longer in a comment
|
|
||||||
comment = false; |
|
||||||
start = true; |
|
||||||
} |
|
||||||
} |
|
||||||
continue; |
|
||||||
} |
|
||||||
else if (found !== -1) { |
|
||||||
if (escapeMarker === -1) { |
|
||||||
args.push(new argument_1.Argument(escapedArg, vscode_languageserver_types_1.Range.create(this.document.positionAt(offset + found), this.document.positionAt(offset + i)))); |
|
||||||
} |
|
||||||
else { |
|
||||||
args.push(new argument_1.Argument(escapedArg, vscode_languageserver_types_1.Range.create(this.document.positionAt(offset + found), this.document.positionAt(offset + escapeMarker)))); |
|
||||||
} |
|
||||||
escapeMarker = -1; |
|
||||||
escapedArg = ""; |
|
||||||
found = -1; |
|
||||||
} |
|
||||||
} |
|
||||||
else if (char === this.escapeChar) { |
|
||||||
let next = fullArgs.charAt(i + 1); |
|
||||||
if (next === ' ' || next === '\t') { |
|
||||||
whitespaceCheck: for (let j = i + 2; j < fullArgs.length; j++) { |
|
||||||
let newlineCheck = fullArgs.charAt(j); |
|
||||||
switch (newlineCheck) { |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
continue; |
|
||||||
case '\r': |
|
||||||
j++; |
|
||||||
case '\n': |
|
||||||
comment = false; |
|
||||||
escaping = true; |
|
||||||
start = true; |
|
||||||
if (found !== -1) { |
|
||||||
escapeMarker = i; |
|
||||||
} |
|
||||||
i = j; |
|
||||||
break whitespaceCheck; |
|
||||||
default: |
|
||||||
escapeMarker = i; |
|
||||||
if (found === -1) { |
|
||||||
i = j - 1; |
|
||||||
} |
|
||||||
break whitespaceCheck; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
else if (next === '\r') { |
|
||||||
comment = false; |
|
||||||
escaping = true; |
|
||||||
start = true; |
|
||||||
if (found !== -1 && escapeMarker === -1) { |
|
||||||
escapeMarker = i; |
|
||||||
} |
|
||||||
i += 2; |
|
||||||
} |
|
||||||
else if (next === '\n') { |
|
||||||
comment = false; |
|
||||||
escaping = true; |
|
||||||
start = true; |
|
||||||
if (found !== -1 && escapeMarker === -1) { |
|
||||||
escapeMarker = i; |
|
||||||
} |
|
||||||
i++; |
|
||||||
} |
|
||||||
else { |
|
||||||
if (escapedWhitespaceDetected && escapeMarker !== -1) { |
|
||||||
args.push(new argument_1.Argument(escapedArg, vscode_languageserver_types_1.Range.create(this.document.positionAt(offset + found), this.document.positionAt(offset + escapeMarker)))); |
|
||||||
escapedArg = ""; |
|
||||||
found = -1; |
|
||||||
} |
|
||||||
escapeMarker = -1; |
|
||||||
escapedWhitespaceDetected = false; |
|
||||||
escaping = false; |
|
||||||
if (next === '$') { |
|
||||||
escapedArg = escapedArg + char + next; |
|
||||||
} |
|
||||||
else if (next === '') { |
|
||||||
// reached EOF, stop processing
|
|
||||||
break; |
|
||||||
} |
|
||||||
else { |
|
||||||
escapedArg = escapedArg + next; |
|
||||||
} |
|
||||||
if (found === -1) { |
|
||||||
found = i; |
|
||||||
} |
|
||||||
i++; |
|
||||||
} |
|
||||||
} |
|
||||||
else if (!comment) { |
|
||||||
if (start && char === '#') { |
|
||||||
comment = true; |
|
||||||
} |
|
||||||
else { |
|
||||||
if (escapedWhitespaceDetected && escapeMarker !== -1) { |
|
||||||
args.push(new argument_1.Argument(escapedArg, vscode_languageserver_types_1.Range.create(this.document.positionAt(offset + found), this.document.positionAt(offset + escapeMarker)))); |
|
||||||
escapedArg = ""; |
|
||||||
found = -1; |
|
||||||
} |
|
||||||
escapedWhitespaceDetected = false; |
|
||||||
escaping = false; |
|
||||||
escapeMarker = -1; |
|
||||||
escapedArg = escapedArg + char; |
|
||||||
if (found === -1) { |
|
||||||
found = i; |
|
||||||
} |
|
||||||
} |
|
||||||
// non-whitespace character detected, reset
|
|
||||||
start = false; |
|
||||||
} |
|
||||||
} |
|
||||||
if (found !== -1) { |
|
||||||
if (escapeMarker === -1) { |
|
||||||
args.push(new argument_1.Argument(escapedArg, vscode_languageserver_types_1.Range.create(this.document.positionAt(offset + found), this.document.positionAt(offset + fullArgs.length)))); |
|
||||||
} |
|
||||||
else { |
|
||||||
args.push(new argument_1.Argument(escapedArg, vscode_languageserver_types_1.Range.create(this.document.positionAt(offset + found), this.document.positionAt(offset + escapeMarker)))); |
|
||||||
} |
|
||||||
} |
|
||||||
return args; |
|
||||||
} |
|
||||||
getExpandedArguments() { |
|
||||||
let args = this.getArguments(); |
|
||||||
for (let i = 0; i < args.length; i++) { |
|
||||||
const argRange = args[i].getRange(); |
|
||||||
let offset = this.document.offsetAt(argRange.start); |
|
||||||
const variables = this.parseVariables(offset, args[i].getValue()); |
|
||||||
const swaps = []; |
|
||||||
let requiresExpansion = false; |
|
||||||
for (let variable of variables) { |
|
||||||
const value = this.dockerfile.resolveVariable(variable.getName(), variable.getNameRange().start.line); |
|
||||||
swaps.push(value); |
|
||||||
requiresExpansion = requiresExpansion || value !== undefined; |
|
||||||
} |
|
||||||
if (requiresExpansion) { |
|
||||||
let expanded = ""; |
|
||||||
for (let j = 0; j < swaps.length; j++) { |
|
||||||
const variableRange = variables[j].getRange(); |
|
||||||
const start = this.document.offsetAt(variableRange.start); |
|
||||||
const end = this.document.offsetAt(variableRange.end); |
|
||||||
if (swaps[j]) { |
|
||||||
// replace variable with its resolved value
|
|
||||||
expanded += this.document.getText().substring(offset, start); |
|
||||||
expanded += swaps[j]; |
|
||||||
offset = end; |
|
||||||
} |
|
||||||
else { |
|
||||||
expanded += this.document.getText().substring(offset, end); |
|
||||||
offset = end; |
|
||||||
} |
|
||||||
} |
|
||||||
const argEnd = this.document.offsetAt(argRange.end); |
|
||||||
if (argEnd !== offset) { |
|
||||||
// if the variable's range doesn't match the argument,
|
|
||||||
// append the remaining text
|
|
||||||
expanded += this.document.getText().substring(offset, argEnd); |
|
||||||
} |
|
||||||
args[i] = new argument_1.Argument(expanded, argRange); |
|
||||||
} |
|
||||||
} |
|
||||||
return args; |
|
||||||
} |
|
||||||
getVariables() { |
|
||||||
const variables = []; |
|
||||||
const args = this.getRawArguments(); |
|
||||||
for (const arg of args) { |
|
||||||
let range = arg.getRange(); |
|
||||||
let rawValue = this.document.getText().substring(this.document.offsetAt(range.start), this.document.offsetAt(range.end)); |
|
||||||
const parsedVariables = this.parseVariables(this.document.offsetAt(arg.getRange().start), rawValue); |
|
||||||
for (const parsedVariable of parsedVariables) { |
|
||||||
variables.push(parsedVariable); |
|
||||||
} |
|
||||||
} |
|
||||||
return variables; |
|
||||||
} |
|
||||||
parseVariables(offset, arg) { |
|
||||||
let variables = []; |
|
||||||
variableLoop: for (let i = 0; i < arg.length; i++) { |
|
||||||
switch (arg.charAt(i)) { |
|
||||||
case this.escapeChar: |
|
||||||
if (arg.charAt(i + 1) === '$') { |
|
||||||
i++; |
|
||||||
} |
|
||||||
break; |
|
||||||
case '$': |
|
||||||
if (arg.charAt(i + 1) === '{') { |
|
||||||
let escapedString = "${"; |
|
||||||
let escapedName = ""; |
|
||||||
let nameEnd = -1; |
|
||||||
let escapedSubstitutionParameter = ""; |
|
||||||
let substitutionStart = -1; |
|
||||||
let substitutionEnd = -1; |
|
||||||
let modifierRead = -1; |
|
||||||
nameLoop: for (let j = i + 2; j < arg.length; j++) { |
|
||||||
let char = arg.charAt(j); |
|
||||||
switch (char) { |
|
||||||
case this.escapeChar: |
|
||||||
for (let k = j + 1; k < arg.length; k++) { |
|
||||||
switch (arg.charAt(k)) { |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
case '\r': |
|
||||||
// ignore whitespace
|
|
||||||
continue; |
|
||||||
case '\n': |
|
||||||
// escape this newline
|
|
||||||
j = k; |
|
||||||
continue nameLoop; |
|
||||||
} |
|
||||||
} |
|
||||||
break; |
|
||||||
case '}': |
|
||||||
escapedString += '}'; |
|
||||||
let modifier = null; |
|
||||||
let modifierRange = null; |
|
||||||
let substitutionParameter = modifierRead !== -1 ? escapedSubstitutionParameter : null; |
|
||||||
let substitutionRange = null; |
|
||||||
if (nameEnd === -1) { |
|
||||||
nameEnd = j; |
|
||||||
} |
|
||||||
else if (nameEnd + 1 === j) { |
|
||||||
modifier = ""; |
|
||||||
modifierRange = vscode_languageserver_types_1.Range.create(this.document.positionAt(offset + nameEnd + 1), this.document.positionAt(offset + nameEnd + 1)); |
|
||||||
} |
|
||||||
else { |
|
||||||
if (substitutionStart === -1) { |
|
||||||
// no substitution parameter found,
|
|
||||||
// but a modifier character existed,
|
|
||||||
// just offset the range by 1 from
|
|
||||||
// the modifier character
|
|
||||||
substitutionStart = modifierRead + 1; |
|
||||||
substitutionEnd = modifierRead + 1; |
|
||||||
} |
|
||||||
else { |
|
||||||
// offset one more from the last
|
|
||||||
// character found
|
|
||||||
substitutionEnd = substitutionEnd + 1; |
|
||||||
} |
|
||||||
modifier = arg.substring(modifierRead, modifierRead + 1); |
|
||||||
modifierRange = vscode_languageserver_types_1.Range.create(this.document.positionAt(offset + modifierRead), this.document.positionAt(offset + modifierRead + 1)); |
|
||||||
substitutionRange = vscode_languageserver_types_1.Range.create(this.document.positionAt(offset + substitutionStart), this.document.positionAt(offset + substitutionEnd)); |
|
||||||
} |
|
||||||
let start = this.document.positionAt(offset + i); |
|
||||||
variables.push(new variable_1.Variable(escapedName, vscode_languageserver_types_1.Range.create(this.document.positionAt(offset + i + 2), this.document.positionAt(offset + nameEnd)), vscode_languageserver_types_1.Range.create(start, this.document.positionAt(offset + j + 1)), modifier, modifierRange, substitutionParameter, substitutionRange, this.dockerfile.resolveVariable(escapedName, start.line) !== undefined, this.isBuildVariable(escapedName, start.line), escapedString)); |
|
||||||
i = j; |
|
||||||
continue variableLoop; |
|
||||||
case ':': |
|
||||||
if (nameEnd === -1) { |
|
||||||
nameEnd = j; |
|
||||||
} |
|
||||||
else if (modifierRead !== -1) { |
|
||||||
if (substitutionStart === -1) { |
|
||||||
substitutionStart = j; |
|
||||||
substitutionEnd = j; |
|
||||||
} |
|
||||||
else { |
|
||||||
substitutionEnd = j; |
|
||||||
} |
|
||||||
escapedSubstitutionParameter += ':'; |
|
||||||
} |
|
||||||
else { |
|
||||||
modifierRead = j; |
|
||||||
} |
|
||||||
escapedString += ':'; |
|
||||||
break; |
|
||||||
case '\n': |
|
||||||
case '\r': |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
break; |
|
||||||
default: |
|
||||||
if (nameEnd === -1) { |
|
||||||
escapedName += char; |
|
||||||
} |
|
||||||
else if (modifierRead !== -1) { |
|
||||||
if (substitutionStart === -1) { |
|
||||||
substitutionStart = j; |
|
||||||
substitutionEnd = j; |
|
||||||
} |
|
||||||
else { |
|
||||||
substitutionEnd = j; |
|
||||||
} |
|
||||||
escapedSubstitutionParameter += char; |
|
||||||
} |
|
||||||
else { |
|
||||||
modifierRead = j; |
|
||||||
} |
|
||||||
escapedString += char; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
// no } found, not a valid variable, stop processing
|
|
||||||
break variableLoop; |
|
||||||
} |
|
||||||
else if (util_1.Util.isWhitespace(arg.charAt(i + 1)) || i === arg.length - 1) { |
|
||||||
// $ followed by whitespace or EOF, ignore this variable
|
|
||||||
continue; |
|
||||||
} |
|
||||||
else { |
|
||||||
let escapedName = ""; |
|
||||||
nameLoop: for (let j = i + 1; j < arg.length; j++) { |
|
||||||
let char = arg.charAt(j); |
|
||||||
switch (char) { |
|
||||||
case '\r': |
|
||||||
case '\n': |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
continue; |
|
||||||
case '$': |
|
||||||
case '\'': |
|
||||||
case '"': |
|
||||||
let varStart = this.document.positionAt(offset + i); |
|
||||||
variables.push(new variable_1.Variable(escapedName, vscode_languageserver_types_1.Range.create(this.document.positionAt(offset + i + 1), this.document.positionAt(offset + j)), vscode_languageserver_types_1.Range.create(varStart, this.document.positionAt(offset + j)), null, null, null, null, this.dockerfile.resolveVariable(escapedName, varStart.line) !== undefined, this.isBuildVariable(escapedName, varStart.line), '$' + escapedName)); |
|
||||||
i = j - 1; |
|
||||||
continue variableLoop; |
|
||||||
case this.escapeChar: |
|
||||||
for (let k = j + 1; k < arg.length; k++) { |
|
||||||
switch (arg.charAt(k)) { |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
case '\r': |
|
||||||
// ignore whitespace
|
|
||||||
continue; |
|
||||||
case '\n': |
|
||||||
// escape this newline
|
|
||||||
j = k; |
|
||||||
continue nameLoop; |
|
||||||
} |
|
||||||
} |
|
||||||
// reached EOF after an escape character
|
|
||||||
let start = this.document.positionAt(offset + i); |
|
||||||
variables.push(new variable_1.Variable(escapedName, vscode_languageserver_types_1.Range.create(this.document.positionAt(offset + i + 1), this.document.positionAt(offset + j)), vscode_languageserver_types_1.Range.create(start, this.document.positionAt(offset + j)), null, null, null, null, this.dockerfile.resolveVariable(escapedName, start.line) !== undefined, this.isBuildVariable(escapedName, start.line), '$' + escapedName)); |
|
||||||
break variableLoop; |
|
||||||
} |
|
||||||
if (char.match(/^[a-z0-9_]+$/i) === null) { |
|
||||||
let varStart = this.document.positionAt(offset + i); |
|
||||||
variables.push(new variable_1.Variable(escapedName, vscode_languageserver_types_1.Range.create(this.document.positionAt(offset + i + 1), this.document.positionAt(offset + j)), vscode_languageserver_types_1.Range.create(varStart, this.document.positionAt(offset + j)), null, null, null, null, this.dockerfile.resolveVariable(escapedName, varStart.line) !== undefined, this.isBuildVariable(escapedName, varStart.line), '$' + escapedName)); |
|
||||||
i = j - 1; |
|
||||||
continue variableLoop; |
|
||||||
} |
|
||||||
escapedName += char; |
|
||||||
} |
|
||||||
let start = this.document.positionAt(offset + i); |
|
||||||
variables.push(new variable_1.Variable(escapedName, vscode_languageserver_types_1.Range.create(this.document.positionAt(offset + i + 1), this.document.positionAt(offset + arg.length)), vscode_languageserver_types_1.Range.create(start, this.document.positionAt(offset + arg.length)), null, null, null, null, this.dockerfile.resolveVariable(escapedName, start.line) !== undefined, this.isBuildVariable(escapedName, start.line), '$' + escapedName)); |
|
||||||
} |
|
||||||
break variableLoop; |
|
||||||
} |
|
||||||
} |
|
||||||
return variables; |
|
||||||
} |
|
||||||
isBuildVariable(variable, line) { |
|
||||||
if (this.getKeyword() === main_1.Keyword.FROM) { |
|
||||||
for (const initialArg of this.dockerfile.getInitialARGs()) { |
|
||||||
const arg = initialArg; |
|
||||||
const property = arg.getProperty(); |
|
||||||
if (property && variable === property.getName()) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
||||||
return undefined; |
|
||||||
} |
|
||||||
let image = this.dockerfile.getContainingImage(vscode_languageserver_types_1.Position.create(line, 0)); |
|
||||||
let envs = image.getENVs(); |
|
||||||
for (let i = envs.length - 1; i >= 0; i--) { |
|
||||||
if (envs[i].isBefore(line)) { |
|
||||||
for (let property of envs[i].getProperties()) { |
|
||||||
if (property.getName() === variable) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
let args = image.getARGs(); |
|
||||||
for (let i = args.length - 1; i >= 0; i--) { |
|
||||||
if (args[i].isBefore(line)) { |
|
||||||
let property = args[i].getProperty(); |
|
||||||
if (property && property.getName() === variable) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return undefined; |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Instruction = Instruction; |
|
@ -1,7 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
import { Dockerfile } from '../dockerfile'; |
|
||||||
import { JSONInstruction } from '../jsonInstruction'; |
|
||||||
export declare class Add extends JSONInstruction { |
|
||||||
constructor(document: TextDocument, range: Range, dockerfile: Dockerfile, escapeChar: string, instruction: string, instructionRange: Range); |
|
||||||
stopSearchingForFlags(argument: string): boolean; |
|
||||||
} |
|
@ -1,12 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
const jsonInstruction_1 = require("../jsonInstruction"); |
|
||||||
class Add extends jsonInstruction_1.JSONInstruction { |
|
||||||
constructor(document, range, dockerfile, escapeChar, instruction, instructionRange) { |
|
||||||
super(document, range, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
} |
|
||||||
stopSearchingForFlags(argument) { |
|
||||||
return argument.indexOf("--") === -1; |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Add = Add; |
|
@ -1,14 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
import { Dockerfile } from '../dockerfile'; |
|
||||||
import { Property } from '../property'; |
|
||||||
import { PropertyInstruction } from '../propertyInstruction'; |
|
||||||
export declare class Arg extends PropertyInstruction { |
|
||||||
private property; |
|
||||||
constructor(document: TextDocument, range: Range, dockerfile: Dockerfile, escapeChar: string, instruction: string, instructionRange: Range); |
|
||||||
/** |
|
||||||
* Returns the variable defined by this ARG. This may be null if |
|
||||||
* this ARG instruction is malformed and has no variable |
|
||||||
* declaration. |
|
||||||
*/ |
|
||||||
getProperty(): Property | null; |
|
||||||
} |
|
@ -1,26 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
const property_1 = require("../property"); |
|
||||||
const propertyInstruction_1 = require("../propertyInstruction"); |
|
||||||
class Arg extends propertyInstruction_1.PropertyInstruction { |
|
||||||
constructor(document, range, dockerfile, escapeChar, instruction, instructionRange) { |
|
||||||
super(document, range, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
this.property = null; |
|
||||||
const args = this.getPropertyArguments(); |
|
||||||
if (args.length === 1) { |
|
||||||
this.property = new property_1.Property(this.document, this.escapeChar, args[0]); |
|
||||||
} |
|
||||||
else { |
|
||||||
this.property = null; |
|
||||||
} |
|
||||||
} |
|
||||||
/** |
|
||||||
* Returns the variable defined by this ARG. This may be null if |
|
||||||
* this ARG instruction is malformed and has no variable |
|
||||||
* declaration. |
|
||||||
*/ |
|
||||||
getProperty() { |
|
||||||
return this.property; |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Arg = Arg; |
|
@ -1,6 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
import { Dockerfile } from '../dockerfile'; |
|
||||||
import { JSONInstruction } from '../jsonInstruction'; |
|
||||||
export declare class Cmd extends JSONInstruction { |
|
||||||
constructor(document: TextDocument, range: Range, dockerfile: Dockerfile, escapeChar: string, instruction: string, instructionRange: Range); |
|
||||||
} |
|
@ -1,9 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
const jsonInstruction_1 = require("../jsonInstruction"); |
|
||||||
class Cmd extends jsonInstruction_1.JSONInstruction { |
|
||||||
constructor(document, range, dockerfile, escapeChar, instruction, instructionRange) { |
|
||||||
super(document, range, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Cmd = Cmd; |
|
@ -1,9 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
import { Dockerfile } from '../dockerfile'; |
|
||||||
import { Flag } from '../flag'; |
|
||||||
import { JSONInstruction } from '../jsonInstruction'; |
|
||||||
export declare class Copy extends JSONInstruction { |
|
||||||
constructor(document: TextDocument, range: Range, dockerfile: Dockerfile, escapeChar: string, instruction: string, instructionRange: Range); |
|
||||||
stopSearchingForFlags(argument: string): boolean; |
|
||||||
getFromFlag(): Flag | null; |
|
||||||
} |
|
@ -1,16 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
const jsonInstruction_1 = require("../jsonInstruction"); |
|
||||||
class Copy extends jsonInstruction_1.JSONInstruction { |
|
||||||
constructor(document, range, dockerfile, escapeChar, instruction, instructionRange) { |
|
||||||
super(document, range, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
} |
|
||||||
stopSearchingForFlags(argument) { |
|
||||||
return argument.indexOf("--") === -1; |
|
||||||
} |
|
||||||
getFromFlag() { |
|
||||||
let flags = super.getFlags(); |
|
||||||
return flags.length === 1 && flags[0].getName() === "from" ? flags[0] : null; |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Copy = Copy; |
|
@ -1,6 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
import { Dockerfile } from '../dockerfile'; |
|
||||||
import { JSONInstruction } from '../jsonInstruction'; |
|
||||||
export declare class Entrypoint extends JSONInstruction { |
|
||||||
constructor(document: TextDocument, range: Range, dockerfile: Dockerfile, escapeChar: string, instruction: string, instructionRange: Range); |
|
||||||
} |
|
@ -1,9 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
const jsonInstruction_1 = require("../jsonInstruction"); |
|
||||||
class Entrypoint extends jsonInstruction_1.JSONInstruction { |
|
||||||
constructor(document, range, dockerfile, escapeChar, instruction, instructionRange) { |
|
||||||
super(document, range, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Entrypoint = Entrypoint; |
|
@ -1,8 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
import { Dockerfile } from '../dockerfile'; |
|
||||||
import { Property } from '../property'; |
|
||||||
import { PropertyInstruction } from '../propertyInstruction'; |
|
||||||
export declare class Env extends PropertyInstruction { |
|
||||||
constructor(document: TextDocument, range: Range, dockerfile: Dockerfile, escapeChar: string, instruction: string, instructionRange: Range); |
|
||||||
getProperties(): Property[]; |
|
||||||
} |
|
@ -1,12 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
const propertyInstruction_1 = require("../propertyInstruction"); |
|
||||||
class Env extends propertyInstruction_1.PropertyInstruction { |
|
||||||
constructor(document, range, dockerfile, escapeChar, instruction, instructionRange) { |
|
||||||
super(document, range, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
} |
|
||||||
getProperties() { |
|
||||||
return super.getProperties(); |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Env = Env; |
|
@ -1,57 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
import { Dockerfile } from '../dockerfile'; |
|
||||||
import { Flag } from '../flag'; |
|
||||||
import { ModifiableInstruction } from '../modifiableInstruction'; |
|
||||||
export declare class From extends ModifiableInstruction { |
|
||||||
constructor(document: TextDocument, range: Range, dockerfile: Dockerfile, escapeChar: string, instruction: string, instructionRange: Range); |
|
||||||
protected stopSearchingForFlags(argument: string): boolean; |
|
||||||
getImage(): string | null; |
|
||||||
/** |
|
||||||
* 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(): string | null; |
|
||||||
/** |
|
||||||
* Returns the range that covers the name of the image used by |
|
||||||
* this instruction. |
|
||||||
* |
|
||||||
* @return the range of the name of this instruction's argument, |
|
||||||
* or null if no image has been specified |
|
||||||
*/ |
|
||||||
getImageNameRange(): Range | 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(): Range | null; |
|
||||||
getImageTag(): string | 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(): Range | null; |
|
||||||
getImageDigest(): string | 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(): Range | null; |
|
||||||
private indexOf; |
|
||||||
private lastIndexOf; |
|
||||||
getRegistry(): string | null; |
|
||||||
getRegistryRange(): Range | null; |
|
||||||
getBuildStage(): string | null; |
|
||||||
getBuildStageRange(): Range | null; |
|
||||||
getPlatformFlag(): Flag | null; |
|
||||||
} |
|
@ -1,198 +0,0 @@ |
|||||||
"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_types_1 = require("vscode-languageserver-types"); |
|
||||||
const modifiableInstruction_1 = require("../modifiableInstruction"); |
|
||||||
class From extends modifiableInstruction_1.ModifiableInstruction { |
|
||||||
constructor(document, range, dockerfile, escapeChar, instruction, instructionRange) { |
|
||||||
super(document, range, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
} |
|
||||||
stopSearchingForFlags(argument) { |
|
||||||
return argument.indexOf("--") === -1; |
|
||||||
} |
|
||||||
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() { |
|
||||||
return this.getRangeContent(this.getImageNameRange()); |
|
||||||
} |
|
||||||
/** |
|
||||||
* Returns the range that covers the name of the image used by |
|
||||||
* this instruction. |
|
||||||
* |
|
||||||
* @return the range of the name of this instruction's argument, |
|
||||||
* or null if no image has been specified |
|
||||||
*/ |
|
||||||
getImageNameRange() { |
|
||||||
let range = this.getImageRange(); |
|
||||||
if (range) { |
|
||||||
let registryRange = this.getRegistryRange(); |
|
||||||
if (registryRange) { |
|
||||||
range.start = this.document.positionAt(this.document.offsetAt(registryRange.end) + 1); |
|
||||||
} |
|
||||||
let tagRange = this.getImageTagRange(); |
|
||||||
let digestRange = this.getImageDigestRange(); |
|
||||||
if (tagRange === null) { |
|
||||||
if (digestRange !== null) { |
|
||||||
range.end = this.document.positionAt(this.document.offsetAt(digestRange.start) - 1); |
|
||||||
} |
|
||||||
} |
|
||||||
else { |
|
||||||
range.end = this.document.positionAt(this.document.offsetAt(tagRange.start) - 1); |
|
||||||
} |
|
||||||
return range; |
|
||||||
} |
|
||||||
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; |
|
||||||
} |
|
||||||
getImageTag() { |
|
||||||
return this.getRangeContent(this.getImageTagRange()); |
|
||||||
} |
|
||||||
/** |
|
||||||
* 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() { |
|
||||||
const range = this.getImageRange(); |
|
||||||
if (range) { |
|
||||||
if (this.getImageDigestRange() === null) { |
|
||||||
let content = this.getRangeContent(range); |
|
||||||
let index = this.lastIndexOf(this.document.offsetAt(range.start), content, ':'); |
|
||||||
// the colon might be for a private registry's port and not a tag
|
|
||||||
if (index > content.indexOf('/')) { |
|
||||||
return vscode_languageserver_types_1.Range.create(range.start.line, range.start.character + index + 1, range.end.line, range.end.character); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
getImageDigest() { |
|
||||||
return this.getRangeContent(this.getImageDigestRange()); |
|
||||||
} |
|
||||||
/** |
|
||||||
* 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 = this.lastIndexOf(this.document.offsetAt(range.start), content, '@'); |
|
||||||
if (index !== -1) { |
|
||||||
return vscode_languageserver_types_1.Range.create(range.start.line, range.start.character + index + 1, range.end.line, range.end.character); |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
indexOf(documentOffset, content, searchString) { |
|
||||||
let index = content.indexOf(searchString); |
|
||||||
const variables = this.getVariables(); |
|
||||||
for (let i = 0; i < variables.length; i++) { |
|
||||||
const position = documentOffset + index; |
|
||||||
const variableRange = variables[i].getRange(); |
|
||||||
if (this.document.offsetAt(variableRange.start) < position && position < this.document.offsetAt(variableRange.end)) { |
|
||||||
const offset = this.document.offsetAt(variableRange.end) - documentOffset; |
|
||||||
const substring = content.substring(offset); |
|
||||||
const subIndex = substring.indexOf(searchString); |
|
||||||
if (subIndex === -1) { |
|
||||||
return -1; |
|
||||||
} |
|
||||||
index = subIndex + offset; |
|
||||||
i = -1; |
|
||||||
continue; |
|
||||||
} |
|
||||||
} |
|
||||||
return index; |
|
||||||
} |
|
||||||
lastIndexOf(documentOffset, content, searchString) { |
|
||||||
let index = content.lastIndexOf(searchString); |
|
||||||
const variables = this.getVariables(); |
|
||||||
for (let i = 0; i < variables.length; i++) { |
|
||||||
const position = documentOffset + index; |
|
||||||
const variableRange = variables[i].getRange(); |
|
||||||
if (this.document.offsetAt(variableRange.start) < position && position < this.document.offsetAt(variableRange.end)) { |
|
||||||
index = content.substring(0, index).lastIndexOf(searchString); |
|
||||||
if (index === -1) { |
|
||||||
return -1; |
|
||||||
} |
|
||||||
i = -1; |
|
||||||
continue; |
|
||||||
} |
|
||||||
} |
|
||||||
return index; |
|
||||||
} |
|
||||||
getRegistry() { |
|
||||||
return this.getRangeContent(this.getRegistryRange()); |
|
||||||
} |
|
||||||
getRegistryRange() { |
|
||||||
const range = this.getImageRange(); |
|
||||||
if (range) { |
|
||||||
const tagRange = this.getImageTagRange(); |
|
||||||
const digestRange = this.getImageDigestRange(); |
|
||||||
if (tagRange === null) { |
|
||||||
if (digestRange !== null) { |
|
||||||
range.end = this.document.positionAt(this.document.offsetAt(digestRange.start) - 1); |
|
||||||
} |
|
||||||
} |
|
||||||
else { |
|
||||||
range.end = this.document.positionAt(this.document.offsetAt(tagRange.start) - 1); |
|
||||||
} |
|
||||||
const content = this.getRangeContent(range); |
|
||||||
const rangeStart = this.document.offsetAt(range.start); |
|
||||||
const portIndex = this.indexOf(rangeStart, content, ':'); |
|
||||||
const dotIndex = this.indexOf(rangeStart, content, '.'); |
|
||||||
const startingSlashIndex = this.indexOf(rangeStart, content, '/'); |
|
||||||
// hostname detected
|
|
||||||
if (portIndex !== -1 || dotIndex !== -1) { |
|
||||||
return vscode_languageserver_types_1.Range.create(range.start, this.document.positionAt(rangeStart + startingSlashIndex)); |
|
||||||
} |
|
||||||
const registry = content.substring(0, startingSlashIndex); |
|
||||||
// localhost registry detected
|
|
||||||
if (registry === 'localhost') { |
|
||||||
return vscode_languageserver_types_1.Range.create(range.start, this.document.positionAt(rangeStart + startingSlashIndex)); |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
getBuildStage() { |
|
||||||
let range = this.getBuildStageRange(); |
|
||||||
return range === null ? null : this.getRangeContent(range); |
|
||||||
} |
|
||||||
getBuildStageRange() { |
|
||||||
let args = this.getArguments(); |
|
||||||
if (args.length > 2 && args[1].getValue().toUpperCase() === "AS") { |
|
||||||
return args[2].getRange(); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
getPlatformFlag() { |
|
||||||
let flags = super.getFlags(); |
|
||||||
return flags.length === 1 && flags[0].getName() === "platform" ? flags[0] : null; |
|
||||||
} |
|
||||||
} |
|
||||||
exports.From = From; |
|
@ -1,9 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
import { Dockerfile } from '../dockerfile'; |
|
||||||
import { Argument } from '../argument'; |
|
||||||
import { ModifiableInstruction } from '../modifiableInstruction'; |
|
||||||
export declare class Healthcheck extends ModifiableInstruction { |
|
||||||
constructor(document: TextDocument, range: Range, dockerfile: Dockerfile, escapeChar: string, instruction: string, instructionRange: Range); |
|
||||||
protected stopSearchingForFlags(argument: string): boolean; |
|
||||||
getSubcommand(): Argument | null; |
|
||||||
} |
|
@ -1,17 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
const modifiableInstruction_1 = require("../modifiableInstruction"); |
|
||||||
class Healthcheck extends modifiableInstruction_1.ModifiableInstruction { |
|
||||||
constructor(document, range, dockerfile, escapeChar, instruction, instructionRange) { |
|
||||||
super(document, range, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
} |
|
||||||
stopSearchingForFlags(argument) { |
|
||||||
argument = argument.toUpperCase(); |
|
||||||
return argument === "CMD" || argument === "NONE"; |
|
||||||
} |
|
||||||
getSubcommand() { |
|
||||||
let args = this.getArguments(); |
|
||||||
return args.length !== 0 ? args[0] : null; |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Healthcheck = Healthcheck; |
|
@ -1,10 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
import { Dockerfile } from '../dockerfile'; |
|
||||||
import { Variable } from '../variable'; |
|
||||||
import { Property } from '../property'; |
|
||||||
import { PropertyInstruction } from '../propertyInstruction'; |
|
||||||
export declare class Label extends PropertyInstruction { |
|
||||||
constructor(document: TextDocument, range: Range, dockerfile: Dockerfile, escapeChar: string, instruction: string, instructionRange: Range); |
|
||||||
getVariables(): Variable[]; |
|
||||||
getProperties(): Property[]; |
|
||||||
} |
|
@ -1,34 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
const propertyInstruction_1 = require("../propertyInstruction"); |
|
||||||
const util_1 = require("../util"); |
|
||||||
class Label extends propertyInstruction_1.PropertyInstruction { |
|
||||||
constructor(document, range, dockerfile, escapeChar, instruction, instructionRange) { |
|
||||||
super(document, range, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
} |
|
||||||
getVariables() { |
|
||||||
const variables = super.getVariables(); |
|
||||||
const properties = this.getProperties(); |
|
||||||
// iterate over all of this LABEL's properties
|
|
||||||
for (const property of properties) { |
|
||||||
const value = property.getUnescapedValue(); |
|
||||||
// check if the value is contained in single quotes,
|
|
||||||
// single quotes would indicate a literal value
|
|
||||||
if (value !== null && value.length > 2 && value.charAt(0) === '\'' && value.charAt(value.length - 1) === '\'') { |
|
||||||
const range = property.getValueRange(); |
|
||||||
for (let i = 0; i < variables.length; i++) { |
|
||||||
// if a variable is in a single quote, remove it from the list
|
|
||||||
if (util_1.Util.isInsideRange(variables[i].getRange().start, range)) { |
|
||||||
variables.splice(i, 1); |
|
||||||
i--; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return variables; |
|
||||||
} |
|
||||||
getProperties() { |
|
||||||
return super.getProperties(); |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Label = Label; |
|
@ -1,10 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
import { Dockerfile } from '../dockerfile'; |
|
||||||
import { Instruction } from '../instruction'; |
|
||||||
export declare class Onbuild extends Instruction { |
|
||||||
constructor(document: TextDocument, range: Range, dockerfile: Dockerfile, escapeChar: string, instruction: string, instructionRange: Range); |
|
||||||
getTrigger(): string | null; |
|
||||||
getTriggerWord(): string | null; |
|
||||||
getTriggerRange(): Range | null; |
|
||||||
getTriggerInstruction(): Instruction | null; |
|
||||||
} |
|
@ -1,34 +0,0 @@ |
|||||||
"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_types_1 = require("vscode-languageserver-types"); |
|
||||||
const parser_1 = require("../parser"); |
|
||||||
const instruction_1 = require("../instruction"); |
|
||||||
class Onbuild extends instruction_1.Instruction { |
|
||||||
constructor(document, range, dockerfile, escapeChar, instruction, instructionRange) { |
|
||||||
super(document, range, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
} |
|
||||||
getTrigger() { |
|
||||||
let trigger = this.getTriggerWord(); |
|
||||||
return trigger === null ? null : trigger.toUpperCase(); |
|
||||||
} |
|
||||||
getTriggerWord() { |
|
||||||
return this.getRangeContent(this.getTriggerRange()); |
|
||||||
} |
|
||||||
getTriggerRange() { |
|
||||||
let args = this.getArguments(); |
|
||||||
return args.length > 0 ? args[0].getRange() : null; |
|
||||||
} |
|
||||||
getTriggerInstruction() { |
|
||||||
let triggerRange = this.getTriggerRange(); |
|
||||||
if (triggerRange === null) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
let args = this.getArguments(); |
|
||||||
return parser_1.Parser.createInstruction(this.document, this.dockerfile, this.escapeChar, vscode_languageserver_types_1.Range.create(args[0].getRange().start, this.getRange().end), this.getTriggerWord(), triggerRange); |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Onbuild = Onbuild; |
|
@ -1,7 +0,0 @@ |
|||||||
import { Range, TextDocument } from 'vscode-languageserver-types'; |
|
||||||
import { Dockerfile } from '../dockerfile'; |
|
||||||
import { JSONInstruction } from '../jsonInstruction'; |
|
||||||
export declare class Run extends JSONInstruction { |
|
||||||
constructor(document: TextDocument, range: Range, dockerfile: Dockerfile, escapeChar: string, instruction: string, instructionRange: Range); |
|
||||||
stopSearchingForFlags(argument: string): boolean; |
|
||||||
} |
|
@ -1,12 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
const jsonInstruction_1 = require("../jsonInstruction"); |
|
||||||
class Run extends jsonInstruction_1.JSONInstruction { |
|
||||||
constructor(document, range, dockerfile, escapeChar, instruction, instructionRange) { |
|
||||||
super(document, range, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
} |
|
||||||
stopSearchingForFlags(argument) { |
|
||||||
return argument.indexOf("--") === -1; |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Run = Run; |
|
@ -1,6 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
import { Dockerfile } from '../dockerfile'; |
|
||||||
import { JSONInstruction } from '../jsonInstruction'; |
|
||||||
export declare class Shell extends JSONInstruction { |
|
||||||
constructor(document: TextDocument, range: Range, dockerfile: Dockerfile, escapeChar: string, instruction: string, instructionRange: Range); |
|
||||||
} |
|
@ -1,9 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
const jsonInstruction_1 = require("../jsonInstruction"); |
|
||||||
class Shell extends jsonInstruction_1.JSONInstruction { |
|
||||||
constructor(document, range, dockerfile, escapeChar, instruction, instructionRange) { |
|
||||||
super(document, range, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Shell = Shell; |
|
@ -1,6 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
import { Dockerfile } from '../dockerfile'; |
|
||||||
import { Instruction } from '../instruction'; |
|
||||||
export declare class Stopsignal extends Instruction { |
|
||||||
constructor(document: TextDocument, range: Range, dockerfile: Dockerfile, escapeChar: string, instruction: string, instructionRange: Range); |
|
||||||
} |
|
@ -1,9 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
const instruction_1 = require("../instruction"); |
|
||||||
class Stopsignal extends instruction_1.Instruction { |
|
||||||
constructor(document, range, dockerfile, escapeChar, instruction, instructionRange) { |
|
||||||
super(document, range, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Stopsignal = Stopsignal; |
|
@ -1,6 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
import { Dockerfile } from '../dockerfile'; |
|
||||||
import { Instruction } from '../instruction'; |
|
||||||
export declare class User extends Instruction { |
|
||||||
constructor(document: TextDocument, range: Range, dockerfile: Dockerfile, escapeChar: string, instruction: string, instructionRange: Range); |
|
||||||
} |
|
@ -1,9 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
const instruction_1 = require("../instruction"); |
|
||||||
class User extends instruction_1.Instruction { |
|
||||||
constructor(document, range, dockerfile, escapeChar, instruction, instructionRange) { |
|
||||||
super(document, range, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
} |
|
||||||
} |
|
||||||
exports.User = User; |
|
@ -1,6 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
import { Dockerfile } from '../dockerfile'; |
|
||||||
import { JSONInstruction } from '../jsonInstruction'; |
|
||||||
export declare class Volume extends JSONInstruction { |
|
||||||
constructor(document: TextDocument, range: Range, dockerfile: Dockerfile, escapeChar: string, instruction: string, instructionRange: Range); |
|
||||||
} |
|
@ -1,9 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
const jsonInstruction_1 = require("../jsonInstruction"); |
|
||||||
class Volume extends jsonInstruction_1.JSONInstruction { |
|
||||||
constructor(document, range, dockerfile, escapeChar, instruction, instructionRange) { |
|
||||||
super(document, range, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Volume = Volume; |
|
@ -1,6 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
import { Dockerfile } from '../dockerfile'; |
|
||||||
import { Instruction } from '../instruction'; |
|
||||||
export declare class Workdir extends Instruction { |
|
||||||
constructor(document: TextDocument, range: Range, dockerfile: Dockerfile, escapeChar: string, instruction: string, instructionRange: Range); |
|
||||||
} |
|
@ -1,9 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
const instruction_1 = require("../instruction"); |
|
||||||
class Workdir extends instruction_1.Instruction { |
|
||||||
constructor(document, range, dockerfile, escapeChar, instruction, instructionRange) { |
|
||||||
super(document, range, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Workdir = Workdir; |
|
@ -1,8 +0,0 @@ |
|||||||
import { Range } from 'vscode-languageserver-types'; |
|
||||||
import { Argument } from './argument'; |
|
||||||
export declare class JSONArgument extends Argument { |
|
||||||
private readonly jsonRange; |
|
||||||
constructor(value: string, range: Range, jsonRange: Range); |
|
||||||
getJSONRange(): Range; |
|
||||||
getJSONValue(): string; |
|
||||||
} |
|
@ -1,18 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
const argument_1 = require("./argument"); |
|
||||||
class JSONArgument extends argument_1.Argument { |
|
||||||
constructor(value, range, jsonRange) { |
|
||||||
super(value, range); |
|
||||||
this.jsonRange = jsonRange; |
|
||||||
} |
|
||||||
getJSONRange() { |
|
||||||
return this.jsonRange; |
|
||||||
} |
|
||||||
getJSONValue() { |
|
||||||
let value = super.getValue(); |
|
||||||
value = value.substring(1, value.length - 1); |
|
||||||
return value; |
|
||||||
} |
|
||||||
} |
|
||||||
exports.JSONArgument = JSONArgument; |
|
@ -1,15 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
import { Dockerfile } from './dockerfile'; |
|
||||||
import { Argument } from './argument'; |
|
||||||
import { JSONArgument } from './jsonArgument'; |
|
||||||
import { ModifiableInstruction } from './modifiableInstruction'; |
|
||||||
export declare class JSONInstruction extends ModifiableInstruction { |
|
||||||
private readonly openingBracket; |
|
||||||
private readonly closingBracket; |
|
||||||
private readonly jsonStrings; |
|
||||||
constructor(document: TextDocument, range: Range, dockerfile: Dockerfile, escapeChar: string, instruction: string, instructionRange: Range); |
|
||||||
protected stopSearchingForFlags(_value: string): boolean; |
|
||||||
getOpeningBracket(): Argument | null; |
|
||||||
getJSONStrings(): JSONArgument[]; |
|
||||||
getClosingBracket(): Argument | null; |
|
||||||
} |
|
@ -1,177 +0,0 @@ |
|||||||
"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_types_1 = require("vscode-languageserver-types"); |
|
||||||
const argument_1 = require("./argument"); |
|
||||||
const jsonArgument_1 = require("./jsonArgument"); |
|
||||||
const modifiableInstruction_1 = require("./modifiableInstruction"); |
|
||||||
class JSONInstruction extends modifiableInstruction_1.ModifiableInstruction { |
|
||||||
constructor(document, range, dockerfile, escapeChar, instruction, instructionRange) { |
|
||||||
super(document, range, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
this.openingBracket = null; |
|
||||||
this.closingBracket = null; |
|
||||||
this.jsonStrings = []; |
|
||||||
const argsContent = this.getRawArgumentsContent(); |
|
||||||
if (argsContent === null) { |
|
||||||
return; |
|
||||||
} |
|
||||||
const args = this.getArguments(); |
|
||||||
if (args.length === 1 && args[0].getValue() === "[]") { |
|
||||||
let argRange = args[0].getRange(); |
|
||||||
this.openingBracket = new argument_1.Argument("[", vscode_languageserver_types_1.Range.create(argRange.start.line, argRange.start.character, argRange.start.line, argRange.start.character + 1)); |
|
||||||
this.closingBracket = new argument_1.Argument("]", vscode_languageserver_types_1.Range.create(argRange.start.line, argRange.start.character + 1, argRange.end.line, argRange.end.character)); |
|
||||||
return; |
|
||||||
} |
|
||||||
else if (args.length === 2 && args[0].getValue() === '[' && args[1].getValue() === ']') { |
|
||||||
this.openingBracket = args[0]; |
|
||||||
this.closingBracket = args[1]; |
|
||||||
return; |
|
||||||
} |
|
||||||
const argsOffset = document.offsetAt(this.getArgumentsRange().start); |
|
||||||
let start = -1; |
|
||||||
let last = ""; |
|
||||||
let quoted = false; |
|
||||||
let escapedArg = ""; |
|
||||||
argsCheck: for (let i = 0; i < argsContent.length; i++) { |
|
||||||
let char = argsContent.charAt(i); |
|
||||||
switch (char) { |
|
||||||
case '[': |
|
||||||
if (last === "") { |
|
||||||
this.openingBracket = new argument_1.Argument("[", vscode_languageserver_types_1.Range.create(document.positionAt(argsOffset + i), document.positionAt(argsOffset + i + 1))); |
|
||||||
last = '['; |
|
||||||
} |
|
||||||
else if (quoted) { |
|
||||||
escapedArg = escapedArg + char; |
|
||||||
} |
|
||||||
else { |
|
||||||
break argsCheck; |
|
||||||
} |
|
||||||
break; |
|
||||||
case '"': |
|
||||||
if (last === '[' || last === ',') { |
|
||||||
start = i; |
|
||||||
quoted = true; |
|
||||||
last = '"'; |
|
||||||
escapedArg = escapedArg + char; |
|
||||||
continue; |
|
||||||
} |
|
||||||
else if (last === '"') { |
|
||||||
if (quoted) { |
|
||||||
escapedArg = escapedArg + char; |
|
||||||
// quoted string done
|
|
||||||
quoted = false; |
|
||||||
this.jsonStrings.push(new jsonArgument_1.JSONArgument(escapedArg, vscode_languageserver_types_1.Range.create(document.positionAt(argsOffset + start), document.positionAt(argsOffset + i + 1)), vscode_languageserver_types_1.Range.create(document.positionAt(argsOffset + start + 1), document.positionAt(argsOffset + i)))); |
|
||||||
escapedArg = ""; |
|
||||||
} |
|
||||||
else { |
|
||||||
// should be a , or a ]
|
|
||||||
break argsCheck; |
|
||||||
} |
|
||||||
} |
|
||||||
else { |
|
||||||
break argsCheck; |
|
||||||
} |
|
||||||
break; |
|
||||||
case ',': |
|
||||||
if (quoted) { |
|
||||||
escapedArg = escapedArg + char; |
|
||||||
} |
|
||||||
else { |
|
||||||
if (last === '"') { |
|
||||||
last = ','; |
|
||||||
} |
|
||||||
else { |
|
||||||
break argsCheck; |
|
||||||
} |
|
||||||
} |
|
||||||
break; |
|
||||||
case ']': |
|
||||||
if (quoted) { |
|
||||||
escapedArg = escapedArg + char; |
|
||||||
} |
|
||||||
else if (last !== "") { |
|
||||||
this.closingBracket = new argument_1.Argument("]", vscode_languageserver_types_1.Range.create(document.positionAt(argsOffset + i), document.positionAt(argsOffset + i + 1))); |
|
||||||
break argsCheck; |
|
||||||
} |
|
||||||
break; |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
break; |
|
||||||
case '\\': |
|
||||||
if (quoted) { |
|
||||||
switch (argsContent.charAt(i + 1)) { |
|
||||||
case '"': |
|
||||||
case '\\': |
|
||||||
escapedArg = escapedArg + argsContent.charAt(i + 1); |
|
||||||
i++; |
|
||||||
continue; |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
escapeCheck: for (let j = i + 2; j < argsContent.length; j++) { |
|
||||||
switch (argsContent.charAt(j)) { |
|
||||||
case '\r': |
|
||||||
// offset one more for \r\n
|
|
||||||
j++; |
|
||||||
case '\n': |
|
||||||
i = j; |
|
||||||
continue argsCheck; |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
break; |
|
||||||
default: |
|
||||||
break escapeCheck; |
|
||||||
} |
|
||||||
} |
|
||||||
break; |
|
||||||
case '\r': |
|
||||||
// offset one more for \r\n
|
|
||||||
i++; |
|
||||||
default: |
|
||||||
i++; |
|
||||||
continue; |
|
||||||
} |
|
||||||
} |
|
||||||
else { |
|
||||||
escapeCheck: for (let j = i + 1; j < argsContent.length; j++) { |
|
||||||
switch (argsContent.charAt(j)) { |
|
||||||
case '\r': |
|
||||||
// offset one more for \r\n
|
|
||||||
j++; |
|
||||||
case '\n': |
|
||||||
i = j; |
|
||||||
continue argsCheck; |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
break; |
|
||||||
default: |
|
||||||
break escapeCheck; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
break argsCheck; |
|
||||||
default: |
|
||||||
if (!quoted) { |
|
||||||
break argsCheck; |
|
||||||
} |
|
||||||
escapedArg = escapedArg + char; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
stopSearchingForFlags(_value) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
getOpeningBracket() { |
|
||||||
return this.openingBracket; |
|
||||||
} |
|
||||||
getJSONStrings() { |
|
||||||
return this.jsonStrings; |
|
||||||
} |
|
||||||
getClosingBracket() { |
|
||||||
return this.closingBracket; |
|
||||||
} |
|
||||||
} |
|
||||||
exports.JSONInstruction = JSONInstruction; |
|
@ -1,10 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
export declare class Line { |
|
||||||
protected readonly document: TextDocument; |
|
||||||
private readonly range; |
|
||||||
constructor(document: TextDocument, range: Range); |
|
||||||
getRange(): Range; |
|
||||||
getTextContent(): string; |
|
||||||
isAfter(line: Line): boolean; |
|
||||||
isBefore(line: number): boolean; |
|
||||||
} |
|
@ -1,21 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
class Line { |
|
||||||
constructor(document, range) { |
|
||||||
this.document = document; |
|
||||||
this.range = range; |
|
||||||
} |
|
||||||
getRange() { |
|
||||||
return this.range; |
|
||||||
} |
|
||||||
getTextContent() { |
|
||||||
return this.document.getText().substring(this.document.offsetAt(this.range.start), this.document.offsetAt(this.range.end)); |
|
||||||
} |
|
||||||
isAfter(line) { |
|
||||||
return this.range.start.line > line.range.start.line; |
|
||||||
} |
|
||||||
isBefore(line) { |
|
||||||
return this.range.start.line < line; |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Line = Line; |
|
@ -1,138 +0,0 @@ |
|||||||
import { Position, Range } from 'vscode-languageserver-types'; |
|
||||||
export { Argument } from './argument'; |
|
||||||
export { JSONArgument } from './jsonArgument'; |
|
||||||
import { Comment } from './comment'; |
|
||||||
export { Comment }; |
|
||||||
export interface ImageTemplate { |
|
||||||
getComments(): Comment[]; |
|
||||||
getInstructions(): Instruction[]; |
|
||||||
getARGs(): Arg[]; |
|
||||||
getCMDs(): Cmd[]; |
|
||||||
getCOPYs(): Copy[]; |
|
||||||
getENTRYPOINTs(): Entrypoint[]; |
|
||||||
getENVs(): Env[]; |
|
||||||
getFROMs(): From[]; |
|
||||||
getHEALTHCHECKs(): Healthcheck[]; |
|
||||||
getOnbuildTriggers(): Instruction[]; |
|
||||||
contains(position: Position): boolean; |
|
||||||
/** |
|
||||||
* Retrieves an array of variable names that are valid at the |
|
||||||
* given line in the Dockerfile (zero-based). If the |
|
||||||
* line is outside the range of the parsed Dockerfile, an empty |
|
||||||
* array will be returned. |
|
||||||
* |
|
||||||
* @param line the interested line, zero-based |
|
||||||
* @return the array of variables that may be used by an |
|
||||||
* instruction at the specified line |
|
||||||
*/ |
|
||||||
getAvailableVariables(line: number): string[]; |
|
||||||
getRange(): Range | null; |
|
||||||
} |
|
||||||
export interface Dockerfile extends ImageTemplate { |
|
||||||
getEscapeCharacter(): string; |
|
||||||
getInitialARGs(): Arg[]; |
|
||||||
getComments(): Comment[]; |
|
||||||
/** |
|
||||||
* Returns the set of instructions that include the given position. |
|
||||||
* |
|
||||||
* @param position the position to search in |
|
||||||
* @return the set of instructions that the given position is in, |
|
||||||
* or null if the position is invalid and is not contained |
|
||||||
* within the Dockerfile |
|
||||||
*/ |
|
||||||
getContainingImage(position: Position): ImageTemplate | null; |
|
||||||
/** |
|
||||||
* @deprecated As of 0.0.18, replaced by getDirectives(). If there |
|
||||||
* is more than one parser directive defined in the |
|
||||||
* Dockerfile, the first one will be returned. |
|
||||||
*/ |
|
||||||
getDirective(): ParserDirective | null; |
|
||||||
/** |
|
||||||
* Retrieves the list of parser directives that have been defined |
|
||||||
* in this Dockerfile. It will be in the order it was defined in |
|
||||||
* the file with the first line of the file being the first |
|
||||||
* directive in the returned array. |
|
||||||
* |
|
||||||
* @return the list of parser directives defined in this |
|
||||||
* Dockerfile in the order they are defind |
|
||||||
* @since 0.0.18 |
|
||||||
*/ |
|
||||||
getDirectives(): ParserDirective[]; |
|
||||||
/** |
|
||||||
* Resolves a variable with the given name at the specified line |
|
||||||
* to its value. If null is returned, then the variable has been |
|
||||||
* defined but no value was given. If undefined is returned, then |
|
||||||
* a variable with the given name has not been defined yet as of |
|
||||||
* the given line. |
|
||||||
* |
|
||||||
* @param variable the name of the variable to resolve |
|
||||||
* @param line the line number that the variable is on, zero-based |
|
||||||
* @return the value of the variable as defined by an ARG or ENV |
|
||||||
* instruction, or null if no value has been specified, or |
|
||||||
* undefined if a variable with the given name has not |
|
||||||
* been defined or if the document does not contain the |
|
||||||
* given line number |
|
||||||
*/ |
|
||||||
resolveVariable(variable: string, line: number): string | null | undefined; |
|
||||||
} |
|
||||||
export { Flag } from './flag'; |
|
||||||
import { Instruction } from './instruction'; |
|
||||||
export { Instruction }; |
|
||||||
export { Line } from './line'; |
|
||||||
import { ParserDirective } from './parserDirective'; |
|
||||||
export { ParserDirective }; |
|
||||||
export { Property } from './property'; |
|
||||||
export { Variable } from './variable'; |
|
||||||
export { Add } from './instructions/add'; |
|
||||||
import { Arg } from './instructions/arg'; |
|
||||||
export { Arg }; |
|
||||||
import { Cmd } from './instructions/cmd'; |
|
||||||
export { Cmd }; |
|
||||||
import { Copy } from './instructions/copy'; |
|
||||||
export { Copy }; |
|
||||||
import { Entrypoint } from './instructions/entrypoint'; |
|
||||||
export { Entrypoint }; |
|
||||||
import { Env } from './instructions/env'; |
|
||||||
export { Env }; |
|
||||||
import { From } from './instructions/from'; |
|
||||||
export { From }; |
|
||||||
import { Healthcheck } from './instructions/healthcheck'; |
|
||||||
export { Healthcheck }; |
|
||||||
export { JSONInstruction } from './jsonInstruction'; |
|
||||||
export { Label } from './instructions/label'; |
|
||||||
export { ModifiableInstruction } from './modifiableInstruction'; |
|
||||||
export { Onbuild } from './instructions/onbuild'; |
|
||||||
export { PropertyInstruction } from './propertyInstruction'; |
|
||||||
export { Shell } from './instructions/shell'; |
|
||||||
export { Stopsignal } from './instructions/stopsignal'; |
|
||||||
export { User } from './instructions/user'; |
|
||||||
export { Volume } from './instructions/volume'; |
|
||||||
export { Workdir } from './instructions/workdir'; |
|
||||||
export declare enum Keyword { |
|
||||||
ADD = "ADD", |
|
||||||
ARG = "ARG", |
|
||||||
CMD = "CMD", |
|
||||||
COPY = "COPY", |
|
||||||
ENTRYPOINT = "ENTRYPOINT", |
|
||||||
ENV = "ENV", |
|
||||||
EXPOSE = "EXPOSE", |
|
||||||
FROM = "FROM", |
|
||||||
HEALTHCHECK = "HEALTHCHECK", |
|
||||||
LABEL = "LABEL", |
|
||||||
MAINTAINER = "MAINTAINER", |
|
||||||
ONBUILD = "ONBUILD", |
|
||||||
RUN = "RUN", |
|
||||||
SHELL = "SHELL", |
|
||||||
STOPSIGNAL = "STOPSIGNAL", |
|
||||||
USER = "USER", |
|
||||||
VOLUME = "VOLUME", |
|
||||||
WORKDIR = "WORKDIR" |
|
||||||
} |
|
||||||
export declare enum Directive { |
|
||||||
escape = "escape", |
|
||||||
syntax = "syntax" |
|
||||||
} |
|
||||||
export declare const DefaultVariables: string[]; |
|
||||||
export declare namespace DockerfileParser { |
|
||||||
function parse(content: string): Dockerfile; |
|
||||||
} |
|
@ -1,97 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
var argument_1 = require("./argument"); |
|
||||||
exports.Argument = argument_1.Argument; |
|
||||||
var jsonArgument_1 = require("./jsonArgument"); |
|
||||||
exports.JSONArgument = jsonArgument_1.JSONArgument; |
|
||||||
const comment_1 = require("./comment"); |
|
||||||
exports.Comment = comment_1.Comment; |
|
||||||
const parser_1 = require("./parser"); |
|
||||||
var flag_1 = require("./flag"); |
|
||||||
exports.Flag = flag_1.Flag; |
|
||||||
const instruction_1 = require("./instruction"); |
|
||||||
exports.Instruction = instruction_1.Instruction; |
|
||||||
var line_1 = require("./line"); |
|
||||||
exports.Line = line_1.Line; |
|
||||||
const parserDirective_1 = require("./parserDirective"); |
|
||||||
exports.ParserDirective = parserDirective_1.ParserDirective; |
|
||||||
var property_1 = require("./property"); |
|
||||||
exports.Property = property_1.Property; |
|
||||||
var variable_1 = require("./variable"); |
|
||||||
exports.Variable = variable_1.Variable; |
|
||||||
var add_1 = require("./instructions/add"); |
|
||||||
exports.Add = add_1.Add; |
|
||||||
const arg_1 = require("./instructions/arg"); |
|
||||||
exports.Arg = arg_1.Arg; |
|
||||||
const cmd_1 = require("./instructions/cmd"); |
|
||||||
exports.Cmd = cmd_1.Cmd; |
|
||||||
const copy_1 = require("./instructions/copy"); |
|
||||||
exports.Copy = copy_1.Copy; |
|
||||||
const entrypoint_1 = require("./instructions/entrypoint"); |
|
||||||
exports.Entrypoint = entrypoint_1.Entrypoint; |
|
||||||
const env_1 = require("./instructions/env"); |
|
||||||
exports.Env = env_1.Env; |
|
||||||
const from_1 = require("./instructions/from"); |
|
||||||
exports.From = from_1.From; |
|
||||||
const healthcheck_1 = require("./instructions/healthcheck"); |
|
||||||
exports.Healthcheck = healthcheck_1.Healthcheck; |
|
||||||
var jsonInstruction_1 = require("./jsonInstruction"); |
|
||||||
exports.JSONInstruction = jsonInstruction_1.JSONInstruction; |
|
||||||
var label_1 = require("./instructions/label"); |
|
||||||
exports.Label = label_1.Label; |
|
||||||
var modifiableInstruction_1 = require("./modifiableInstruction"); |
|
||||||
exports.ModifiableInstruction = modifiableInstruction_1.ModifiableInstruction; |
|
||||||
var onbuild_1 = require("./instructions/onbuild"); |
|
||||||
exports.Onbuild = onbuild_1.Onbuild; |
|
||||||
var propertyInstruction_1 = require("./propertyInstruction"); |
|
||||||
exports.PropertyInstruction = propertyInstruction_1.PropertyInstruction; |
|
||||||
var shell_1 = require("./instructions/shell"); |
|
||||||
exports.Shell = shell_1.Shell; |
|
||||||
var stopsignal_1 = require("./instructions/stopsignal"); |
|
||||||
exports.Stopsignal = stopsignal_1.Stopsignal; |
|
||||||
var user_1 = require("./instructions/user"); |
|
||||||
exports.User = user_1.User; |
|
||||||
var volume_1 = require("./instructions/volume"); |
|
||||||
exports.Volume = volume_1.Volume; |
|
||||||
var workdir_1 = require("./instructions/workdir"); |
|
||||||
exports.Workdir = workdir_1.Workdir; |
|
||||||
var Keyword; |
|
||||||
(function (Keyword) { |
|
||||||
Keyword["ADD"] = "ADD"; |
|
||||||
Keyword["ARG"] = "ARG"; |
|
||||||
Keyword["CMD"] = "CMD"; |
|
||||||
Keyword["COPY"] = "COPY"; |
|
||||||
Keyword["ENTRYPOINT"] = "ENTRYPOINT"; |
|
||||||
Keyword["ENV"] = "ENV"; |
|
||||||
Keyword["EXPOSE"] = "EXPOSE"; |
|
||||||
Keyword["FROM"] = "FROM"; |
|
||||||
Keyword["HEALTHCHECK"] = "HEALTHCHECK"; |
|
||||||
Keyword["LABEL"] = "LABEL"; |
|
||||||
Keyword["MAINTAINER"] = "MAINTAINER"; |
|
||||||
Keyword["ONBUILD"] = "ONBUILD"; |
|
||||||
Keyword["RUN"] = "RUN"; |
|
||||||
Keyword["SHELL"] = "SHELL"; |
|
||||||
Keyword["STOPSIGNAL"] = "STOPSIGNAL"; |
|
||||||
Keyword["USER"] = "USER"; |
|
||||||
Keyword["VOLUME"] = "VOLUME"; |
|
||||||
Keyword["WORKDIR"] = "WORKDIR"; |
|
||||||
})(Keyword = exports.Keyword || (exports.Keyword = {})); |
|
||||||
var Directive; |
|
||||||
(function (Directive) { |
|
||||||
Directive["escape"] = "escape"; |
|
||||||
Directive["syntax"] = "syntax"; |
|
||||||
})(Directive = exports.Directive || (exports.Directive = {})); |
|
||||||
exports.DefaultVariables = [ |
|
||||||
"FTP_PROXY", "ftp_proxy", |
|
||||||
"HTTP_PROXY", "http_proxy", |
|
||||||
"HTTPS_PROXY", "https_proxy", |
|
||||||
"NO_PROXY", "no_proxy" |
|
||||||
]; |
|
||||||
var DockerfileParser; |
|
||||||
(function (DockerfileParser) { |
|
||||||
function parse(content) { |
|
||||||
let parser = new parser_1.Parser(); |
|
||||||
return parser.parse(content); |
|
||||||
} |
|
||||||
DockerfileParser.parse = parse; |
|
||||||
})(DockerfileParser = exports.DockerfileParser || (exports.DockerfileParser = {})); |
|
@ -1,12 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
import { Dockerfile } from './dockerfile'; |
|
||||||
import { Argument } from './argument'; |
|
||||||
import { Flag } from './flag'; |
|
||||||
import { Instruction } from './instruction'; |
|
||||||
export declare abstract class ModifiableInstruction extends Instruction { |
|
||||||
private flags; |
|
||||||
constructor(document: TextDocument, range: Range, dockerfile: Dockerfile, escapeChar: string, instruction: string, instructionRange: Range); |
|
||||||
protected abstract stopSearchingForFlags(value: string): boolean; |
|
||||||
getFlags(): Flag[]; |
|
||||||
getArguments(): Argument[]; |
|
||||||
} |
|
@ -1,84 +0,0 @@ |
|||||||
"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_types_1 = require("vscode-languageserver-types"); |
|
||||||
const flag_1 = require("./flag"); |
|
||||||
const instruction_1 = require("./instruction"); |
|
||||||
class ModifiableInstruction extends instruction_1.Instruction { |
|
||||||
constructor(document, range, dockerfile, escapeChar, instruction, instructionRange) { |
|
||||||
super(document, range, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
} |
|
||||||
getFlags() { |
|
||||||
if (!this.flags) { |
|
||||||
this.flags = []; |
|
||||||
for (let arg of this.getArguments()) { |
|
||||||
let value = arg.getValue(); |
|
||||||
if (this.stopSearchingForFlags(value)) { |
|
||||||
return this.flags; |
|
||||||
} |
|
||||||
else if (value.indexOf("--") === 0) { |
|
||||||
let range = arg.getRange(); |
|
||||||
let rawValue = this.document.getText().substring(this.document.offsetAt(range.start), this.document.offsetAt(range.end)); |
|
||||||
let nameIndex = value.indexOf('='); |
|
||||||
let index = rawValue.indexOf('='); |
|
||||||
let firstMatch = false; |
|
||||||
let secondMatch = false; |
|
||||||
let startIndex = -1; |
|
||||||
nameSearchLoop: for (let i = 0; i < rawValue.length; i++) { |
|
||||||
switch (rawValue.charAt(i)) { |
|
||||||
case '\\': |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
case '\r': |
|
||||||
case '\n': |
|
||||||
break; |
|
||||||
case '-': |
|
||||||
if (secondMatch) { |
|
||||||
startIndex = i; |
|
||||||
break nameSearchLoop; |
|
||||||
} |
|
||||||
else if (firstMatch) { |
|
||||||
secondMatch = true; |
|
||||||
} |
|
||||||
else { |
|
||||||
firstMatch = true; |
|
||||||
} |
|
||||||
break; |
|
||||||
default: |
|
||||||
startIndex = i; |
|
||||||
break nameSearchLoop; |
|
||||||
} |
|
||||||
} |
|
||||||
let nameStart = this.document.positionAt(this.document.offsetAt(range.start) + startIndex); |
|
||||||
if (index === -1) { |
|
||||||
this.flags.push(new flag_1.Flag(this.document, range, value.substring(2), vscode_languageserver_types_1.Range.create(nameStart, range.end), null, null)); |
|
||||||
} |
|
||||||
else if (index === value.length - 1) { |
|
||||||
let nameEnd = this.document.positionAt(this.document.offsetAt(range.start) + index); |
|
||||||
this.flags.push(new flag_1.Flag(this.document, range, value.substring(2, index), vscode_languageserver_types_1.Range.create(nameStart, nameEnd), "", vscode_languageserver_types_1.Range.create(range.end, range.end))); |
|
||||||
} |
|
||||||
else { |
|
||||||
let nameEnd = this.document.positionAt(this.document.offsetAt(range.start) + index); |
|
||||||
this.flags.push(new flag_1.Flag(this.document, range, value.substring(2, nameIndex), vscode_languageserver_types_1.Range.create(nameStart, nameEnd), value.substring(nameIndex + 1), vscode_languageserver_types_1.Range.create(this.document.positionAt(this.document.offsetAt(range.start) + index + 1), range.end))); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return this.flags; |
|
||||||
} |
|
||||||
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; |
|
@ -1,9 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
import { Instruction } from './instruction'; |
|
||||||
import { Dockerfile } from './dockerfile'; |
|
||||||
export declare class Parser { |
|
||||||
private escapeChar; |
|
||||||
static createInstruction(document: TextDocument, dockerfile: Dockerfile, escapeChar: string, lineRange: Range, instruction: string, instructionRange: Range): Instruction; |
|
||||||
private getParserDirectives; |
|
||||||
parse(buffer: string): Dockerfile; |
|
||||||
} |
|
@ -1,401 +0,0 @@ |
|||||||
/* -------------------------------------------------------------------------------------------- |
|
||||||
* 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 }); |
|
||||||
const vscode_languageserver_types_1 = require("vscode-languageserver-types"); |
|
||||||
const comment_1 = require("./comment"); |
|
||||||
const parserDirective_1 = require("./parserDirective"); |
|
||||||
const instruction_1 = require("./instruction"); |
|
||||||
const add_1 = require("./instructions/add"); |
|
||||||
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 label_1 = require("./instructions/label"); |
|
||||||
const onbuild_1 = require("./instructions/onbuild"); |
|
||||||
const run_1 = require("./instructions/run"); |
|
||||||
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"); |
|
||||||
class Parser { |
|
||||||
constructor() { |
|
||||||
this.escapeChar = null; |
|
||||||
} |
|
||||||
static createInstruction(document, dockerfile, escapeChar, lineRange, instruction, instructionRange) { |
|
||||||
switch (instruction.toUpperCase()) { |
|
||||||
case "ADD": |
|
||||||
return new add_1.Add(document, lineRange, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
case "ARG": |
|
||||||
return new arg_1.Arg(document, lineRange, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
case "CMD": |
|
||||||
return new cmd_1.Cmd(document, lineRange, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
case "COPY": |
|
||||||
return new copy_1.Copy(document, lineRange, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
case "ENTRYPOINT": |
|
||||||
return new entrypoint_1.Entrypoint(document, lineRange, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
case "ENV": |
|
||||||
return new env_1.Env(document, lineRange, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
case "FROM": |
|
||||||
return new from_1.From(document, lineRange, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
case "HEALTHCHECK": |
|
||||||
return new healthcheck_1.Healthcheck(document, lineRange, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
case "LABEL": |
|
||||||
return new label_1.Label(document, lineRange, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
case "ONBUILD": |
|
||||||
return new onbuild_1.Onbuild(document, lineRange, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
case "RUN": |
|
||||||
return new run_1.Run(document, lineRange, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
case "SHELL": |
|
||||||
return new shell_1.Shell(document, lineRange, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
case "STOPSIGNAL": |
|
||||||
return new stopsignal_1.Stopsignal(document, lineRange, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
case "WORKDIR": |
|
||||||
return new workdir_1.Workdir(document, lineRange, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
case "USER": |
|
||||||
return new user_1.User(document, lineRange, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
case "VOLUME": |
|
||||||
return new volume_1.Volume(document, lineRange, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
} |
|
||||||
return new instruction_1.Instruction(document, lineRange, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
} |
|
||||||
getParserDirectives(document, buffer) { |
|
||||||
// reset the escape directive in between runs
|
|
||||||
const directives = []; |
|
||||||
this.escapeChar = ''; |
|
||||||
directiveCheck: for (let i = 0; i < buffer.length; i++) { |
|
||||||
switch (buffer.charAt(i)) { |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
break; |
|
||||||
case '\r': |
|
||||||
case '\n': |
|
||||||
// blank lines stop the parsing of directives immediately
|
|
||||||
break directiveCheck; |
|
||||||
case '#': |
|
||||||
let commentStart = i; |
|
||||||
let directiveStart = -1; |
|
||||||
let directiveEnd = -1; |
|
||||||
for (let j = i + 1; j < buffer.length; j++) { |
|
||||||
let char = buffer.charAt(j); |
|
||||||
switch (char) { |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
if (directiveStart !== -1 && directiveEnd === -1) { |
|
||||||
directiveEnd = j; |
|
||||||
} |
|
||||||
break; |
|
||||||
case '\r': |
|
||||||
case '\n': |
|
||||||
break directiveCheck; |
|
||||||
case '=': |
|
||||||
let valueStart = -1; |
|
||||||
let valueEnd = -1; |
|
||||||
if (directiveEnd === -1) { |
|
||||||
directiveEnd = j; |
|
||||||
} |
|
||||||
// assume the line ends with the file
|
|
||||||
let lineEnd = buffer.length; |
|
||||||
directiveValue: for (let k = j + 1; k < buffer.length; k++) { |
|
||||||
char = buffer.charAt(k); |
|
||||||
switch (char) { |
|
||||||
case '\r': |
|
||||||
case '\n': |
|
||||||
if (valueStart !== -1 && valueEnd === -1) { |
|
||||||
valueEnd = k; |
|
||||||
} |
|
||||||
// line break found, reset
|
|
||||||
lineEnd = k; |
|
||||||
break directiveValue; |
|
||||||
case '\t': |
|
||||||
case ' ': |
|
||||||
if (valueStart !== -1 && valueEnd === -1) { |
|
||||||
valueEnd = k; |
|
||||||
} |
|
||||||
continue; |
|
||||||
default: |
|
||||||
if (valueStart === -1) { |
|
||||||
valueStart = k; |
|
||||||
} |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
let lineRange = vscode_languageserver_types_1.Range.create(document.positionAt(commentStart), document.positionAt(lineEnd)); |
|
||||||
if (directiveStart === -1) { |
|
||||||
// no directive, it's a regular comment
|
|
||||||
break directiveCheck; |
|
||||||
} |
|
||||||
if (valueStart === -1) { |
|
||||||
// no non-whitespace characters found, highlight all the characters then
|
|
||||||
valueStart = j + 1; |
|
||||||
valueEnd = lineEnd; |
|
||||||
} |
|
||||||
else if (valueEnd === -1) { |
|
||||||
// reached EOF
|
|
||||||
valueEnd = buffer.length; |
|
||||||
} |
|
||||||
let nameRange = vscode_languageserver_types_1.Range.create(document.positionAt(directiveStart), document.positionAt(directiveEnd)); |
|
||||||
let valueRange = vscode_languageserver_types_1.Range.create(document.positionAt(valueStart), document.positionAt(valueEnd)); |
|
||||||
directives.push(new parserDirective_1.ParserDirective(document, lineRange, nameRange, valueRange)); |
|
||||||
directiveStart = -1; |
|
||||||
if (buffer.charAt(valueEnd) === '\r') { |
|
||||||
// skip over the \r
|
|
||||||
i = valueEnd + 1; |
|
||||||
} |
|
||||||
else { |
|
||||||
i = valueEnd; |
|
||||||
} |
|
||||||
continue directiveCheck; |
|
||||||
default: |
|
||||||
if (directiveStart === -1) { |
|
||||||
directiveStart = j; |
|
||||||
} |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
break; |
|
||||||
default: |
|
||||||
break directiveCheck; |
|
||||||
} |
|
||||||
} |
|
||||||
return directives; |
|
||||||
} |
|
||||||
parse(buffer) { |
|
||||||
let document = vscode_languageserver_types_1.TextDocument.create("", "", 0, buffer); |
|
||||||
let dockerfile = new dockerfile_1.Dockerfile(document); |
|
||||||
let directives = this.getParserDirectives(document, buffer); |
|
||||||
let offset = 0; |
|
||||||
this.escapeChar = '\\'; |
|
||||||
if (directives.length > 0) { |
|
||||||
dockerfile.setDirectives(directives); |
|
||||||
this.escapeChar = dockerfile.getEscapeCharacter(); |
|
||||||
// start parsing after the directives
|
|
||||||
offset = document.offsetAt(vscode_languageserver_types_1.Position.create(directives.length, 0)); |
|
||||||
} |
|
||||||
lineCheck: for (let i = offset; i < buffer.length; i++) { |
|
||||||
let char = buffer.charAt(i); |
|
||||||
switch (char) { |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
case '\r': |
|
||||||
case '\n': |
|
||||||
break; |
|
||||||
case '#': |
|
||||||
for (let j = i + 1; j < buffer.length; j++) { |
|
||||||
char = buffer.charAt(j); |
|
||||||
switch (char) { |
|
||||||
case '\r': |
|
||||||
dockerfile.addComment(new comment_1.Comment(document, vscode_languageserver_types_1.Range.create(document.positionAt(i), document.positionAt(j)))); |
|
||||||
// offset one more for \r\n
|
|
||||||
i = j + 1; |
|
||||||
continue lineCheck; |
|
||||||
case '\n': |
|
||||||
dockerfile.addComment(new comment_1.Comment(document, vscode_languageserver_types_1.Range.create(document.positionAt(i), document.positionAt(j)))); |
|
||||||
i = j; |
|
||||||
continue lineCheck; |
|
||||||
} |
|
||||||
} |
|
||||||
// reached EOF
|
|
||||||
let range = vscode_languageserver_types_1.Range.create(document.positionAt(i), document.positionAt(buffer.length)); |
|
||||||
dockerfile.addComment(new comment_1.Comment(document, range)); |
|
||||||
break lineCheck; |
|
||||||
default: |
|
||||||
let instruction = char; |
|
||||||
let instructionStart = i; |
|
||||||
let instructionEnd = -1; |
|
||||||
let lineRange = null; |
|
||||||
let instructionRange = null; |
|
||||||
let escapedInstruction = false; |
|
||||||
instructionCheck: for (let j = i + 1; j < buffer.length; j++) { |
|
||||||
char = buffer.charAt(j); |
|
||||||
switch (char) { |
|
||||||
case this.escapeChar: |
|
||||||
escapedInstruction = true; |
|
||||||
char = buffer.charAt(j + 1); |
|
||||||
if (char === '\r') { |
|
||||||
// skip two for \r\n
|
|
||||||
j += 2; |
|
||||||
} |
|
||||||
else if (char === '\n') { |
|
||||||
j++; |
|
||||||
} |
|
||||||
else if (char === ' ' || char === '\t') { |
|
||||||
for (let k = j + 2; k < buffer.length; k++) { |
|
||||||
switch (buffer.charAt(k)) { |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
break; |
|
||||||
case '\r': |
|
||||||
// skip another for \r\n
|
|
||||||
j = k + 1; |
|
||||||
continue instructionCheck; |
|
||||||
case '\n': |
|
||||||
j = k; |
|
||||||
continue instructionCheck; |
|
||||||
default: |
|
||||||
instructionEnd = j + 1; |
|
||||||
instruction = instruction + this.escapeChar; |
|
||||||
j = k - 2; |
|
||||||
continue instructionCheck; |
|
||||||
} |
|
||||||
} |
|
||||||
instructionEnd = j + 1; |
|
||||||
instruction = instruction + this.escapeChar; |
|
||||||
break instructionCheck; |
|
||||||
} |
|
||||||
else { |
|
||||||
instructionEnd = j + 1; |
|
||||||
instruction = instruction + this.escapeChar; |
|
||||||
} |
|
||||||
break; |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
if (escapedInstruction) { |
|
||||||
// on an escaped newline, need to search for non-whitespace
|
|
||||||
escapeCheck: for (let k = j + 1; k < buffer.length; k++) { |
|
||||||
switch (buffer.charAt(k)) { |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
break; |
|
||||||
case '\r': |
|
||||||
// skip another for \r\n
|
|
||||||
j = k + 1; |
|
||||||
continue instructionCheck; |
|
||||||
case '\n': |
|
||||||
j = k; |
|
||||||
continue instructionCheck; |
|
||||||
default: |
|
||||||
break escapeCheck; |
|
||||||
} |
|
||||||
} |
|
||||||
escapedInstruction = false; |
|
||||||
} |
|
||||||
if (instructionEnd === -1) { |
|
||||||
instructionEnd = j; |
|
||||||
} |
|
||||||
let escaped = false; |
|
||||||
argumentsCheck: for (let k = j + 1; k < buffer.length; k++) { |
|
||||||
switch (buffer.charAt(k)) { |
|
||||||
case '\r': |
|
||||||
case '\n': |
|
||||||
if (escaped) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
i = k; |
|
||||||
lineRange = vscode_languageserver_types_1.Range.create(document.positionAt(instructionStart), document.positionAt(k)); |
|
||||||
instructionRange = vscode_languageserver_types_1.Range.create(document.positionAt(instructionStart), document.positionAt(instructionEnd)); |
|
||||||
dockerfile.addInstruction(Parser.createInstruction(document, dockerfile, this.escapeChar, lineRange, instruction, instructionRange)); |
|
||||||
continue lineCheck; |
|
||||||
case this.escapeChar: |
|
||||||
let next = buffer.charAt(k + 1); |
|
||||||
if (next === '\n') { |
|
||||||
escaped = true; |
|
||||||
k++; |
|
||||||
} |
|
||||||
else if (next === '\r') { |
|
||||||
escaped = true; |
|
||||||
// skip two chars for \r\n
|
|
||||||
k = k + 2; |
|
||||||
} |
|
||||||
else if (next === ' ' || next === '\t') { |
|
||||||
escapeCheck: for (let l = k + 2; l < buffer.length; l++) { |
|
||||||
switch (buffer.charAt(l)) { |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
break; |
|
||||||
case '\r': |
|
||||||
// skip another char for \r\n
|
|
||||||
escaped = true; |
|
||||||
k = l + 1; |
|
||||||
break escapeCheck; |
|
||||||
case '\n': |
|
||||||
escaped = true; |
|
||||||
k = l; |
|
||||||
break escapeCheck; |
|
||||||
default: |
|
||||||
k = l; |
|
||||||
break escapeCheck; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
continue; |
|
||||||
case '#': |
|
||||||
if (escaped) { |
|
||||||
for (let l = k + 1; l < buffer.length; l++) { |
|
||||||
switch (buffer.charAt(l)) { |
|
||||||
case '\r': |
|
||||||
dockerfile.addComment(new comment_1.Comment(document, vscode_languageserver_types_1.Range.create(document.positionAt(k), document.positionAt(l)))); |
|
||||||
// offset one more for \r\n
|
|
||||||
k = l + 1; |
|
||||||
continue argumentsCheck; |
|
||||||
case '\n': |
|
||||||
let range = vscode_languageserver_types_1.Range.create(document.positionAt(k), document.positionAt(l)); |
|
||||||
dockerfile.addComment(new comment_1.Comment(document, range)); |
|
||||||
k = l; |
|
||||||
continue argumentsCheck; |
|
||||||
} |
|
||||||
} |
|
||||||
let range = vscode_languageserver_types_1.Range.create(document.positionAt(k), document.positionAt(buffer.length)); |
|
||||||
dockerfile.addComment(new comment_1.Comment(document, range)); |
|
||||||
break argumentsCheck; |
|
||||||
} |
|
||||||
break; |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
break; |
|
||||||
default: |
|
||||||
if (escaped) { |
|
||||||
escaped = false; |
|
||||||
} |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
// reached EOF
|
|
||||||
lineRange = vscode_languageserver_types_1.Range.create(document.positionAt(instructionStart), document.positionAt(buffer.length)); |
|
||||||
instructionRange = vscode_languageserver_types_1.Range.create(document.positionAt(instructionStart), document.positionAt(instructionEnd)); |
|
||||||
dockerfile.addInstruction(Parser.createInstruction(document, dockerfile, this.escapeChar, lineRange, instruction, instructionRange)); |
|
||||||
break lineCheck; |
|
||||||
case '\r': |
|
||||||
if (instructionEnd === -1) { |
|
||||||
instructionEnd = j; |
|
||||||
} |
|
||||||
// skip for \r\n
|
|
||||||
j++; |
|
||||||
case '\n': |
|
||||||
if (escapedInstruction) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (instructionEnd === -1) { |
|
||||||
instructionEnd = j; |
|
||||||
} |
|
||||||
lineRange = vscode_languageserver_types_1.Range.create(document.positionAt(instructionStart), document.positionAt(instructionEnd)); |
|
||||||
dockerfile.addInstruction(Parser.createInstruction(document, dockerfile, this.escapeChar, lineRange, instruction, lineRange)); |
|
||||||
i = j; |
|
||||||
continue lineCheck; |
|
||||||
default: |
|
||||||
instructionEnd = j + 1; |
|
||||||
instruction = instruction + char; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
// reached EOF
|
|
||||||
if (instructionEnd === -1) { |
|
||||||
instructionEnd = buffer.length; |
|
||||||
} |
|
||||||
lineRange = vscode_languageserver_types_1.Range.create(document.positionAt(instructionStart), document.positionAt(instructionEnd)); |
|
||||||
dockerfile.addInstruction(Parser.createInstruction(document, dockerfile, this.escapeChar, lineRange, instruction, lineRange)); |
|
||||||
break lineCheck; |
|
||||||
} |
|
||||||
} |
|
||||||
dockerfile.organizeComments(); |
|
||||||
return dockerfile; |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Parser = Parser; |
|
@ -1,14 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
import { Directive } from './main'; |
|
||||||
import { Line } from './line'; |
|
||||||
export declare class ParserDirective extends Line { |
|
||||||
private readonly nameRange; |
|
||||||
private readonly valueRange; |
|
||||||
constructor(document: TextDocument, range: Range, nameRange: Range, valueRange: Range); |
|
||||||
toString(): string; |
|
||||||
getNameRange(): Range; |
|
||||||
getValueRange(): Range; |
|
||||||
getName(): string; |
|
||||||
getValue(): string; |
|
||||||
getDirective(): Directive | null; |
|
||||||
} |
|
@ -1,31 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
const main_1 = require("./main"); |
|
||||||
const line_1 = require("./line"); |
|
||||||
class ParserDirective extends line_1.Line { |
|
||||||
constructor(document, range, nameRange, valueRange) { |
|
||||||
super(document, range); |
|
||||||
this.nameRange = nameRange; |
|
||||||
this.valueRange = valueRange; |
|
||||||
} |
|
||||||
toString() { |
|
||||||
return "# " + this.getName() + '=' + this.getValue(); |
|
||||||
} |
|
||||||
getNameRange() { |
|
||||||
return this.nameRange; |
|
||||||
} |
|
||||||
getValueRange() { |
|
||||||
return this.valueRange; |
|
||||||
} |
|
||||||
getName() { |
|
||||||
return this.document.getText().substring(this.document.offsetAt(this.nameRange.start), this.document.offsetAt(this.nameRange.end)); |
|
||||||
} |
|
||||||
getValue() { |
|
||||||
return this.document.getText().substring(this.document.offsetAt(this.valueRange.start), this.document.offsetAt(this.valueRange.end)); |
|
||||||
} |
|
||||||
getDirective() { |
|
||||||
const directive = main_1.Directive[this.getName().toLowerCase()]; |
|
||||||
return directive === undefined ? null : directive; |
|
||||||
} |
|
||||||
} |
|
||||||
exports.ParserDirective = ParserDirective; |
|
@ -1,51 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
import { Argument } from './argument'; |
|
||||||
export declare class Property { |
|
||||||
private document; |
|
||||||
private escapeChar; |
|
||||||
private readonly range; |
|
||||||
private readonly nameRange; |
|
||||||
private readonly name; |
|
||||||
private readonly assignmentOperatorRange; |
|
||||||
private readonly assignmentOperator; |
|
||||||
private readonly valueRange; |
|
||||||
private readonly value; |
|
||||||
constructor(document: TextDocument, escapeChar: string, arg: Argument, arg2?: Argument); |
|
||||||
getRange(): Range; |
|
||||||
getName(): string; |
|
||||||
getNameRange(): Range; |
|
||||||
getValue(): string | null; |
|
||||||
getValueRange(): Range | null; |
|
||||||
/** |
|
||||||
* Retrieves the operator used for delimiting between the name and |
|
||||||
* value of this property. This will either be the "=" character |
|
||||||
* or null if a character was not used or if this property has no |
|
||||||
* value defined. |
|
||||||
*/ |
|
||||||
getAssignmentOperator(): string | null; |
|
||||||
getAssignmentOperatorRange(): Range | null; |
|
||||||
/** |
|
||||||
* Returns the value of this property including any enclosing |
|
||||||
* single or double quotes and relevant escape characters. |
|
||||||
* Escaped newlines and its associated contiguous whitespace |
|
||||||
* characters however will not be returned as they are deemed to |
|
||||||
* be uninteresting to clients trying to return a Dockerfile. |
|
||||||
* |
|
||||||
* @return the unescaped value of this property or null if this |
|
||||||
* property has no associated value |
|
||||||
*/ |
|
||||||
getUnescapedValue(): string | null; |
|
||||||
private static getNameRange; |
|
||||||
private static getValueRange; |
|
||||||
/** |
|
||||||
* Returns the actual value of this key-value pair. The value will |
|
||||||
* have its escape characters removed if applicable. If the value |
|
||||||
* spans multiple lines and there are comments nested within the |
|
||||||
* lines, they too will be removed. |
|
||||||
* |
|
||||||
* @return the value that this key-value pair will actually be, may |
|
||||||
* be null if no value is defined, may be the empty string |
|
||||||
* if the value only consists of whitespace |
|
||||||
*/ |
|
||||||
private static getValue; |
|
||||||
} |
|
@ -1,343 +0,0 @@ |
|||||||
"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_types_1 = require("vscode-languageserver-types"); |
|
||||||
const util_1 = require("./util"); |
|
||||||
class Property { |
|
||||||
constructor(document, escapeChar, arg, arg2) { |
|
||||||
this.assignmentOperatorRange = null; |
|
||||||
this.assignmentOperator = null; |
|
||||||
this.valueRange = null; |
|
||||||
this.value = null; |
|
||||||
this.document = document; |
|
||||||
this.escapeChar = escapeChar; |
|
||||||
this.nameRange = Property.getNameRange(document, arg); |
|
||||||
let value = document.getText().substring(document.offsetAt(this.nameRange.start), document.offsetAt(this.nameRange.end)); |
|
||||||
this.name = Property.getValue(value, escapeChar); |
|
||||||
if (arg2) { |
|
||||||
this.valueRange = arg2.getRange(); |
|
||||||
value = document.getText().substring(document.offsetAt(this.valueRange.start), document.offsetAt(this.valueRange.end)); |
|
||||||
this.value = Property.getValue(value, escapeChar); |
|
||||||
this.range = vscode_languageserver_types_1.Range.create(this.nameRange.start, this.valueRange.end); |
|
||||||
} |
|
||||||
else { |
|
||||||
let argRange = arg.getRange(); |
|
||||||
if (this.nameRange.start.line === argRange.start.line |
|
||||||
&& this.nameRange.start.character === argRange.start.character |
|
||||||
&& this.nameRange.end.line === argRange.end.line |
|
||||||
&& this.nameRange.end.character === argRange.end.character) { |
|
||||||
} |
|
||||||
else { |
|
||||||
this.valueRange = Property.getValueRange(document, arg); |
|
||||||
value = document.getText().substring(document.offsetAt(this.valueRange.start), document.offsetAt(this.valueRange.end)); |
|
||||||
this.value = Property.getValue(value, escapeChar); |
|
||||||
this.assignmentOperatorRange = vscode_languageserver_types_1.Range.create(this.nameRange.end, this.valueRange.start); |
|
||||||
this.assignmentOperator = "="; |
|
||||||
} |
|
||||||
this.range = argRange; |
|
||||||
} |
|
||||||
} |
|
||||||
getRange() { |
|
||||||
return this.range; |
|
||||||
} |
|
||||||
getName() { |
|
||||||
return this.name; |
|
||||||
} |
|
||||||
getNameRange() { |
|
||||||
return this.nameRange; |
|
||||||
} |
|
||||||
getValue() { |
|
||||||
return this.value; |
|
||||||
} |
|
||||||
getValueRange() { |
|
||||||
return this.valueRange; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Retrieves the operator used for delimiting between the name and |
|
||||||
* value of this property. This will either be the "=" character |
|
||||||
* or null if a character was not used or if this property has no |
|
||||||
* value defined. |
|
||||||
*/ |
|
||||||
getAssignmentOperator() { |
|
||||||
return this.assignmentOperator; |
|
||||||
} |
|
||||||
getAssignmentOperatorRange() { |
|
||||||
return this.assignmentOperatorRange; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Returns the value of this property including any enclosing |
|
||||||
* single or double quotes and relevant escape characters. |
|
||||||
* Escaped newlines and its associated contiguous whitespace |
|
||||||
* characters however will not be returned as they are deemed to |
|
||||||
* be uninteresting to clients trying to return a Dockerfile. |
|
||||||
* |
|
||||||
* @return the unescaped value of this property or null if this |
|
||||||
* property has no associated value |
|
||||||
*/ |
|
||||||
getUnescapedValue() { |
|
||||||
if (this.valueRange === null) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
let escaped = false; |
|
||||||
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); |
|
||||||
switch (char) { |
|
||||||
case this.escapeChar: |
|
||||||
for (let j = i + 1; j < value.length; j++) { |
|
||||||
switch (value.charAt(j)) { |
|
||||||
case '\r': |
|
||||||
j++; |
|
||||||
case '\n': |
|
||||||
escaped = true; |
|
||||||
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; |
|
||||||
break; |
|
||||||
case '\r': |
|
||||||
case '\n': |
|
||||||
break; |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
if (!escaped) { |
|
||||||
rawValue = rawValue + char; |
|
||||||
} |
|
||||||
break; |
|
||||||
case '#': |
|
||||||
if (escaped) { |
|
||||||
for (let j = i + 1; j < value.length; j++) { |
|
||||||
switch (value.charAt(j)) { |
|
||||||
case '\r': |
|
||||||
j++; |
|
||||||
case '\n': |
|
||||||
i = j; |
|
||||||
continue rawLoop; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
else { |
|
||||||
rawValue = rawValue + char; |
|
||||||
} |
|
||||||
break; |
|
||||||
default: |
|
||||||
rawValue = rawValue + char; |
|
||||||
escaped = false; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
return rawValue; |
|
||||||
} |
|
||||||
static getNameRange(document, arg) { |
|
||||||
let value = arg.getValue(); |
|
||||||
let index = value.indexOf('='); |
|
||||||
if (index !== -1) { |
|
||||||
let initial = value.charAt(0); |
|
||||||
let before = value.charAt(index - 1); |
|
||||||
// check if content before the equals sign are in quotes
|
|
||||||
// "var"=value
|
|
||||||
// 'var'=value
|
|
||||||
// otherwise, just assume it's a standard definition
|
|
||||||
// var=value
|
|
||||||
if ((initial === '"' && before === '"') || (initial === '\'' && before === '\'') || (initial !== '"' && initial !== '\'')) { |
|
||||||
return vscode_languageserver_types_1.Range.create(arg.getRange().start, document.positionAt(document.offsetAt(arg.getRange().start) + index)); |
|
||||||
} |
|
||||||
} |
|
||||||
// no '=' found, just defined the property's name
|
|
||||||
return arg.getRange(); |
|
||||||
} |
|
||||||
static getValueRange(document, arg) { |
|
||||||
return vscode_languageserver_types_1.Range.create(document.positionAt(document.offsetAt(arg.getRange().start) + arg.getValue().indexOf('=') + 1), document.positionAt(document.offsetAt(arg.getRange().end))); |
|
||||||
} |
|
||||||
/** |
|
||||||
* Returns the actual value of this key-value pair. The value will |
|
||||||
* have its escape characters removed if applicable. If the value |
|
||||||
* spans multiple lines and there are comments nested within the |
|
||||||
* lines, they too will be removed. |
|
||||||
* |
|
||||||
* @return the value that this key-value pair will actually be, may |
|
||||||
* be null if no value is defined, may be the empty string |
|
||||||
* if the value only consists of whitespace |
|
||||||
*/ |
|
||||||
static getValue(value, escapeChar) { |
|
||||||
let escaped = false; |
|
||||||
const skip = util_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); |
|
||||||
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 = ""; |
|
||||||
let start = 0; |
|
||||||
parseValue: for (let i = 0; i < value.length; i++) { |
|
||||||
let char = value.charAt(i); |
|
||||||
switch (char) { |
|
||||||
case escapeChar: |
|
||||||
if (i + 1 === value.length) { |
|
||||||
escapedValue = escapedValue + escapeChar; |
|
||||||
break parseValue; |
|
||||||
} |
|
||||||
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': |
|
||||||
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; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
if (inDouble) { |
|
||||||
if (char === '\r') { |
|
||||||
escaped = true; |
|
||||||
i = i + 2; |
|
||||||
} |
|
||||||
else if (char === '\n') { |
|
||||||
escaped = true; |
|
||||||
i++; |
|
||||||
} |
|
||||||
else if (char !== '"') { |
|
||||||
if (char === escapeChar) { |
|
||||||
i++; |
|
||||||
} |
|
||||||
escapedValue = escapedValue + escapeChar; |
|
||||||
} |
|
||||||
continue parseValue; |
|
||||||
} |
|
||||||
else if (inSingle || literal) { |
|
||||||
if (char === '\r') { |
|
||||||
escaped = true; |
|
||||||
i = i + 2; |
|
||||||
} |
|
||||||
else if (char === '\n') { |
|
||||||
escaped = true; |
|
||||||
i++; |
|
||||||
} |
|
||||||
else { |
|
||||||
escapedValue = escapedValue + escapeChar; |
|
||||||
} |
|
||||||
continue parseValue; |
|
||||||
} |
|
||||||
else if (char === escapeChar) { |
|
||||||
// double escape, append one and move on
|
|
||||||
escapedValue = escapedValue + escapeChar; |
|
||||||
i++; |
|
||||||
} |
|
||||||
else if (char === '\r') { |
|
||||||
escaped = true; |
|
||||||
// offset one more for \r\n
|
|
||||||
i = i + 2; |
|
||||||
} |
|
||||||
else if (char === '\n') { |
|
||||||
escaped = true; |
|
||||||
i++; |
|
||||||
start = i; |
|
||||||
} |
|
||||||
else { |
|
||||||
// any other escapes are simply ignored
|
|
||||||
escapedValue = escapedValue + char; |
|
||||||
i++; |
|
||||||
} |
|
||||||
break; |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
if (escaped && commentCheck === -1) { |
|
||||||
commentCheck = i; |
|
||||||
} |
|
||||||
escapedValue = escapedValue + char; |
|
||||||
break; |
|
||||||
case '\r': |
|
||||||
i++; |
|
||||||
case '\n': |
|
||||||
if (escaped && commentCheck !== -1) { |
|
||||||
// rollback and remove the whitespace that was previously appended
|
|
||||||
escapedValue = escapedValue.substring(0, escapedValue.length - (i - commentCheck - 1)); |
|
||||||
commentCheck = -1; |
|
||||||
} |
|
||||||
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; |
|
||||||
} |
|
||||||
newlineCheck: for (let j = i + 1; j < value.length; j++) { |
|
||||||
switch (value.charAt(j)) { |
|
||||||
case '\r': |
|
||||||
j++; |
|
||||||
case '\n': |
|
||||||
i = j; |
|
||||||
break newlineCheck; |
|
||||||
} |
|
||||||
} |
|
||||||
continue parseValue; |
|
||||||
} |
|
||||||
default: |
|
||||||
if (escaped) { |
|
||||||
escaped = false; |
|
||||||
commentCheck = -1; |
|
||||||
} |
|
||||||
escapedValue = escapedValue + char; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
return escapedValue; |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Property = Property; |
|
@ -1,23 +0,0 @@ |
|||||||
import { TextDocument, Range } from 'vscode-languageserver-types'; |
|
||||||
import { Dockerfile } from './dockerfile'; |
|
||||||
import { Instruction } from './instruction'; |
|
||||||
import { Property } from './property'; |
|
||||||
import { Argument } from './argument'; |
|
||||||
export declare abstract class PropertyInstruction extends Instruction { |
|
||||||
private properties; |
|
||||||
constructor(document: TextDocument, range: Range, dockerfile: Dockerfile, escapeChar: string, instruction: string, instructionRange: Range); |
|
||||||
getProperties(): Property[]; |
|
||||||
/** |
|
||||||
* Goes from the back of the string and returns the first |
|
||||||
* non-whitespace character that is found. If an escape character |
|
||||||
* is found with newline characters, the escape character will |
|
||||||
* not be considered a non-whitespace character and its index in |
|
||||||
* the string will not be returned. |
|
||||||
* |
|
||||||
* @param content the string to search through |
|
||||||
* @return the index in the string for the first non-whitespace |
|
||||||
* character when searching from the end of the string |
|
||||||
*/ |
|
||||||
private findTrailingNonWhitespace; |
|
||||||
getPropertyArguments(): Argument[]; |
|
||||||
} |
|
@ -1,323 +0,0 @@ |
|||||||
"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_types_1 = require("vscode-languageserver-types"); |
|
||||||
const instruction_1 = require("./instruction"); |
|
||||||
const property_1 = require("./property"); |
|
||||||
const argument_1 = require("./argument"); |
|
||||||
const util_1 = require("./util"); |
|
||||||
class PropertyInstruction extends instruction_1.Instruction { |
|
||||||
constructor(document, range, dockerfile, escapeChar, instruction, instructionRange) { |
|
||||||
super(document, range, dockerfile, escapeChar, instruction, instructionRange); |
|
||||||
this.properties = undefined; |
|
||||||
} |
|
||||||
getProperties() { |
|
||||||
if (this.properties === undefined) { |
|
||||||
let args = this.getPropertyArguments(); |
|
||||||
if (args.length === 0) { |
|
||||||
this.properties = []; |
|
||||||
} |
|
||||||
else if (args.length === 1) { |
|
||||||
this.properties = [new property_1.Property(this.document, this.escapeChar, args[0])]; |
|
||||||
} |
|
||||||
else if (args.length === 2) { |
|
||||||
if (args[0].getValue().indexOf('=') === -1) { |
|
||||||
this.properties = [new property_1.Property(this.document, this.escapeChar, args[0], args[1])]; |
|
||||||
} |
|
||||||
else { |
|
||||||
this.properties = [ |
|
||||||
new property_1.Property(this.document, this.escapeChar, args[0]), |
|
||||||
new property_1.Property(this.document, this.escapeChar, args[1]) |
|
||||||
]; |
|
||||||
} |
|
||||||
} |
|
||||||
else if (args[0].getValue().indexOf('=') === -1) { |
|
||||||
let text = this.document.getText(); |
|
||||||
let start = args[1].getRange().start; |
|
||||||
let end = args[args.length - 1].getRange().end; |
|
||||||
text = text.substring(this.document.offsetAt(start), this.document.offsetAt(end)); |
|
||||||
this.properties = [new property_1.Property(this.document, this.escapeChar, args[0], new argument_1.Argument(text, vscode_languageserver_types_1.Range.create(args[1].getRange().start, args[args.length - 1].getRange().end)))]; |
|
||||||
} |
|
||||||
else { |
|
||||||
this.properties = []; |
|
||||||
for (let i = 0; i < args.length; i++) { |
|
||||||
this.properties.push(new property_1.Property(this.document, this.escapeChar, args[i])); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return this.properties; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Goes from the back of the string and returns the first |
|
||||||
* non-whitespace character that is found. If an escape character |
|
||||||
* is found with newline characters, the escape character will |
|
||||||
* not be considered a non-whitespace character and its index in |
|
||||||
* the string will not be returned. |
|
||||||
* |
|
||||||
* @param content the string to search through |
|
||||||
* @return the index in the string for the first non-whitespace |
|
||||||
* character when searching from the end of the string |
|
||||||
*/ |
|
||||||
findTrailingNonWhitespace(content) { |
|
||||||
// loop back to find the first non-whitespace character
|
|
||||||
let index = content.length; |
|
||||||
whitespaceCheck: for (let i = content.length - 1; i >= 0; i--) { |
|
||||||
switch (content.charAt(i)) { |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
continue; |
|
||||||
case '\n': |
|
||||||
if (content.charAt(i - 1) === '\r') { |
|
||||||
i = i - 1; |
|
||||||
} |
|
||||||
case '\r': |
|
||||||
newlineCheck: for (let j = i - 1; j >= 0; j--) { |
|
||||||
switch (content.charAt(j)) { |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
case '\r': |
|
||||||
case '\n': |
|
||||||
case this.escapeChar: |
|
||||||
continue; |
|
||||||
default: |
|
||||||
index = j; |
|
||||||
break newlineCheck; |
|
||||||
} |
|
||||||
} |
|
||||||
break whitespaceCheck; |
|
||||||
default: |
|
||||||
index = i; |
|
||||||
break whitespaceCheck; |
|
||||||
} |
|
||||||
} |
|
||||||
return index; |
|
||||||
} |
|
||||||
getPropertyArguments() { |
|
||||||
const args = []; |
|
||||||
let range = this.getInstructionRange(); |
|
||||||
let instructionNameEndOffset = this.document.offsetAt(range.end); |
|
||||||
let extra = instructionNameEndOffset - this.document.offsetAt(range.start); |
|
||||||
let content = this.getTextContent(); |
|
||||||
let fullArgs = content.substring(extra); |
|
||||||
let start = util_1.Util.findLeadingNonWhitespace(fullArgs, this.escapeChar); |
|
||||||
if (start === -1) { |
|
||||||
// only whitespace found, no arguments
|
|
||||||
return []; |
|
||||||
} |
|
||||||
const startPosition = this.document.positionAt(instructionNameEndOffset + start); |
|
||||||
// records whether the parser has just processed an escaped newline or not,
|
|
||||||
// if our starting position is not on the same line as the instruction then
|
|
||||||
// the start of the content is already on an escaped line
|
|
||||||
let escaped = range.start.line !== startPosition.line; |
|
||||||
// flag to track if the last character was an escape character
|
|
||||||
let endingEscape = false; |
|
||||||
// position before the first escape character was hit
|
|
||||||
let mark = -1; |
|
||||||
let end = this.findTrailingNonWhitespace(fullArgs); |
|
||||||
content = fullArgs.substring(start, end + 1); |
|
||||||
let argStart = escaped ? -1 : 0; |
|
||||||
let spaced = false; |
|
||||||
argumentLoop: for (let i = 0; i < content.length; i++) { |
|
||||||
let char = content.charAt(i); |
|
||||||
switch (char) { |
|
||||||
case this.escapeChar: |
|
||||||
if (i + 1 === content.length) { |
|
||||||
endingEscape = true; |
|
||||||
break argumentLoop; |
|
||||||
} |
|
||||||
if (!escaped) { |
|
||||||
mark = i; |
|
||||||
} |
|
||||||
switch (content.charAt(i + 1)) { |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
if (!util_1.Util.isWhitespace(content.charAt(i + 2))) { |
|
||||||
// space was escaped, continue as normal
|
|
||||||
i = i + 1; |
|
||||||
continue argumentLoop; |
|
||||||
} |
|
||||||
// whitespace encountered, need to figure out if it extends to EOL
|
|
||||||
whitespaceCheck: for (let j = i + 2; j < content.length; j++) { |
|
||||||
switch (content.charAt(j)) { |
|
||||||
case '\r': |
|
||||||
// offset one more for \r\n
|
|
||||||
j++; |
|
||||||
case '\n': |
|
||||||
// whitespace only, safe to skip
|
|
||||||
escaped = true; |
|
||||||
i = j; |
|
||||||
continue argumentLoop; |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
// ignore whitespace
|
|
||||||
break; |
|
||||||
default: |
|
||||||
// whitespace doesn't extend to EOL, create an argument
|
|
||||||
args.push(new argument_1.Argument(content.substring(argStart, i), vscode_languageserver_types_1.Range.create(this.document.positionAt(instructionNameEndOffset + start + argStart), this.document.positionAt(instructionNameEndOffset + start + i + 2)))); |
|
||||||
argStart = j; |
|
||||||
break whitespaceCheck; |
|
||||||
} |
|
||||||
} |
|
||||||
// go back and start processing the encountered non-whitespace character
|
|
||||||
i = argStart - 1; |
|
||||||
continue argumentLoop; |
|
||||||
case '\r': |
|
||||||
// offset one more for \r\n
|
|
||||||
i++; |
|
||||||
case '\n': |
|
||||||
// immediately followed by a newline, skip the newline
|
|
||||||
escaped = true; |
|
||||||
i = i + 1; |
|
||||||
continue argumentLoop; |
|
||||||
case this.escapeChar: |
|
||||||
// double escape found, skip it and move on
|
|
||||||
if (argStart === -1) { |
|
||||||
argStart = i; |
|
||||||
} |
|
||||||
i = i + 1; |
|
||||||
continue argumentLoop; |
|
||||||
default: |
|
||||||
if (argStart === -1) { |
|
||||||
argStart = i; |
|
||||||
} |
|
||||||
// non-whitespace encountered, skip the escape and process the
|
|
||||||
// character normally
|
|
||||||
continue argumentLoop; |
|
||||||
} |
|
||||||
case '\'': |
|
||||||
case '"': |
|
||||||
if (argStart === -1) { |
|
||||||
argStart = i; |
|
||||||
} |
|
||||||
for (let j = i + 1; j < content.length; j++) { |
|
||||||
switch (content.charAt(j)) { |
|
||||||
case char: |
|
||||||
if (content.charAt(j + 1) !== ' ' && content.charAt(j + 1) !== '') { |
|
||||||
// there is more content after this quote,
|
|
||||||
// continue so that it is all processed as
|
|
||||||
// one single argument
|
|
||||||
i = j; |
|
||||||
continue argumentLoop; |
|
||||||
} |
|
||||||
args.push(new argument_1.Argument(content.substring(argStart, j + 1), vscode_languageserver_types_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; |
|
||||||
} |
|
||||||
} |
|
||||||
break argumentLoop; |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
if (escaped) { |
|
||||||
// consider there to be a space only if an argument
|
|
||||||
// is not spanning multiple lines
|
|
||||||
if (argStart !== -1) { |
|
||||||
spaced = true; |
|
||||||
} |
|
||||||
} |
|
||||||
else if (argStart !== -1) { |
|
||||||
args.push(new argument_1.Argument(content.substring(argStart, i), vscode_languageserver_types_1.Range.create(this.document.positionAt(instructionNameEndOffset + start + argStart), this.document.positionAt(instructionNameEndOffset + start + i)))); |
|
||||||
argStart = -1; |
|
||||||
} |
|
||||||
break; |
|
||||||
case '\r': |
|
||||||
// offset one more for \r\n
|
|
||||||
i++; |
|
||||||
case '\n': |
|
||||||
spaced = false; |
|
||||||
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': |
|
||||||
j++; |
|
||||||
case '\n': |
|
||||||
i = j; |
|
||||||
spaced = false; |
|
||||||
continue argumentLoop; |
|
||||||
} |
|
||||||
} |
|
||||||
// went to the end without finding a newline,
|
|
||||||
// the comment was the last line in the instruction,
|
|
||||||
// just stop parsing, create an argument if needed
|
|
||||||
if (argStart !== -1) { |
|
||||||
let value = content.substring(argStart, mark); |
|
||||||
args.push(new argument_1.Argument(value, vscode_languageserver_types_1.Range.create(this.document.positionAt(instructionNameEndOffset + start + argStart), this.document.positionAt(instructionNameEndOffset + start + mark)))); |
|
||||||
argStart = -1; |
|
||||||
} |
|
||||||
break argumentLoop; |
|
||||||
} |
|
||||||
else if (argStart === -1) { |
|
||||||
argStart = i; |
|
||||||
} |
|
||||||
break; |
|
||||||
default: |
|
||||||
if (spaced) { |
|
||||||
if (argStart !== -1) { |
|
||||||
args.push(new argument_1.Argument(content.substring(argStart, mark), vscode_languageserver_types_1.Range.create(this.document.positionAt(instructionNameEndOffset + start + argStart), this.document.positionAt(instructionNameEndOffset + start + mark)))); |
|
||||||
argStart = -1; |
|
||||||
} |
|
||||||
spaced = false; |
|
||||||
} |
|
||||||
escaped = false; |
|
||||||
if (argStart === -1) { |
|
||||||
argStart = i; |
|
||||||
} |
|
||||||
// variable detected
|
|
||||||
if (char === '$' && content.charAt(i + 1) === '{') { |
|
||||||
let singleQuotes = false; |
|
||||||
let doubleQuotes = false; |
|
||||||
let escaped = false; |
|
||||||
for (let j = i + 1; j < content.length; j++) { |
|
||||||
switch (content.charAt(j)) { |
|
||||||
case this.escapeChar: |
|
||||||
escaped = true; |
|
||||||
break; |
|
||||||
case '\r': |
|
||||||
case '\n': |
|
||||||
break; |
|
||||||
case '\'': |
|
||||||
singleQuotes = !singleQuotes; |
|
||||||
escaped = false; |
|
||||||
break; |
|
||||||
case '"': |
|
||||||
doubleQuotes = !doubleQuotes; |
|
||||||
escaped = false; |
|
||||||
break; |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
if (escaped || singleQuotes || doubleQuotes) { |
|
||||||
break; |
|
||||||
} |
|
||||||
i = j - 1; |
|
||||||
continue argumentLoop; |
|
||||||
case '}': |
|
||||||
i = j; |
|
||||||
continue argumentLoop; |
|
||||||
default: |
|
||||||
escaped = false; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
break argumentLoop; |
|
||||||
} |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
if (argStart !== -1 && argStart !== content.length) { |
|
||||||
let end = endingEscape ? content.length - 1 : content.length; |
|
||||||
let value = content.substring(argStart, end); |
|
||||||
args.push(new argument_1.Argument(value, vscode_languageserver_types_1.Range.create(this.document.positionAt(instructionNameEndOffset + start + argStart), this.document.positionAt(instructionNameEndOffset + start + end)))); |
|
||||||
} |
|
||||||
return args; |
|
||||||
} |
|
||||||
} |
|
||||||
exports.PropertyInstruction = PropertyInstruction; |
|
@ -1,13 +0,0 @@ |
|||||||
import { Range, Position } from 'vscode-languageserver-types'; |
|
||||||
export declare class Util { |
|
||||||
static isWhitespace(char: string): boolean; |
|
||||||
static isNewline(char: string): boolean; |
|
||||||
static findLeadingNonWhitespace(content: string, escapeChar: string): number; |
|
||||||
/** |
|
||||||
* Determines if the given position is contained within the given range. |
|
||||||
* |
|
||||||
* @param position the position to check |
|
||||||
* @param range the range to see if the position is inside of |
|
||||||
*/ |
|
||||||
static isInsideRange(position: Position, range: Range): boolean; |
|
||||||
} |
|
@ -1,67 +0,0 @@ |
|||||||
/* -------------------------------------------------------------------------------------------- |
|
||||||
* 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 }); |
|
||||||
class Util { |
|
||||||
static isWhitespace(char) { |
|
||||||
return char === ' ' || char === '\t' || Util.isNewline(char); |
|
||||||
} |
|
||||||
static isNewline(char) { |
|
||||||
return char === '\r' || char === '\n'; |
|
||||||
} |
|
||||||
static findLeadingNonWhitespace(content, escapeChar) { |
|
||||||
whitespaceCheck: for (let i = 0; i < content.length; i++) { |
|
||||||
switch (content.charAt(i)) { |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
continue; |
|
||||||
case escapeChar: |
|
||||||
escapeCheck: for (let j = i + 1; j < content.length; j++) { |
|
||||||
switch (content.charAt(j)) { |
|
||||||
case ' ': |
|
||||||
case '\t': |
|
||||||
continue; |
|
||||||
case '\r': |
|
||||||
// offset one more for \r\n
|
|
||||||
i = j + 1; |
|
||||||
continue whitespaceCheck; |
|
||||||
case '\n': |
|
||||||
i = j; |
|
||||||
continue whitespaceCheck; |
|
||||||
default: |
|
||||||
break escapeCheck; |
|
||||||
} |
|
||||||
} |
|
||||||
// found an escape character and then reached EOF
|
|
||||||
return -1; |
|
||||||
default: |
|
||||||
return i; |
|
||||||
} |
|
||||||
} |
|
||||||
// only possible if the content is the empty string
|
|
||||||
return -1; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Determines if the given position is contained within the given range. |
|
||||||
* |
|
||||||
* @param position the position to check |
|
||||||
* @param range the range to see if the position is inside of |
|
||||||
*/ |
|
||||||
static isInsideRange(position, range) { |
|
||||||
if (range.start.line === range.end.line) { |
|
||||||
return range.start.line === position.line |
|
||||||
&& range.start.character <= position.character |
|
||||||
&& position.character <= range.end.character; |
|
||||||
} |
|
||||||
else if (range.start.line === position.line) { |
|
||||||
return range.start.character <= position.character; |
|
||||||
} |
|
||||||
else if (range.end.line === position.line) { |
|
||||||
return position.character <= range.end.character; |
|
||||||
} |
|
||||||
return range.start.line < position.line && position.line < range.end.line; |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Util = Util; |
|
@ -1,66 +0,0 @@ |
|||||||
import { Range } from 'vscode-languageserver-types'; |
|
||||||
export declare class Variable { |
|
||||||
private readonly name; |
|
||||||
private readonly nameRange; |
|
||||||
private readonly range; |
|
||||||
private readonly modifier; |
|
||||||
private readonly modifierRange; |
|
||||||
private readonly substitutionParameter; |
|
||||||
private readonly substitutionRange; |
|
||||||
private readonly defined; |
|
||||||
private readonly buildVariable; |
|
||||||
private readonly stringValue; |
|
||||||
constructor(name: string, nameRange: Range, range: Range, modifier: string | null, modifierRange: Range | null, substitutionParameter: string | null, substitutionRange: Range | null, defined: boolean, buildVariable: boolean, stringValue: string); |
|
||||||
toString(): string; |
|
||||||
getName(): string; |
|
||||||
getNameRange(): Range; |
|
||||||
/** |
|
||||||
* Returns the range of the entire variable. This includes the symbols for |
|
||||||
* the declaration of the variable such as the $, {, and } symbols. |
|
||||||
* |
|
||||||
* @return the range in the document that this variable encompasses in its |
|
||||||
* entirety |
|
||||||
*/ |
|
||||||
getRange(): Range; |
|
||||||
/** |
|
||||||
* Returns the modifier character that has been set for |
|
||||||
* specifying how this variable should be expanded and resolved. |
|
||||||
* If this variable is ${variable:+value} then the modifier |
|
||||||
* character is '+'. Will be the empty string if the variable is |
|
||||||
* declared as ${variable:}. Otherwise, will be null if this |
|
||||||
* variable will not use variable substitution at all (such as |
|
||||||
* ${variable} or $variable). |
|
||||||
* |
|
||||||
* @return this variable's modifier character, or the empty |
|
||||||
* string if it does not have one, or null if this |
|
||||||
* variable will not use variable substitution |
|
||||||
*/ |
|
||||||
getModifier(): string | null; |
|
||||||
getModifierRange(): Range | null; |
|
||||||
/** |
|
||||||
* Returns the parameter that will be used for substitution if |
|
||||||
* this variable uses modifiers to define how its value should be |
|
||||||
* resolved. If this variable is ${variable:+value} then the |
|
||||||
* substitution value will be 'value'. Will be the empty string |
|
||||||
* if the variable is declared as ${variable:+} or some other |
|
||||||
* variant where the only thing that follows the modifier |
|
||||||
* character (excluding considerations of escape characters and |
|
||||||
* so on) is the variable's closing bracket. May be null if this |
|
||||||
* variable does not have a modifier character defined (such as |
|
||||||
* ${variable} or $variable). |
|
||||||
* |
|
||||||
* @return this variable's substitution parameter, or the empty |
|
||||||
* string if it does not have one, or null if there is |
|
||||||
* not one defined |
|
||||||
*/ |
|
||||||
getSubstitutionParameter(): string | null; |
|
||||||
getSubstitutionRange(): Range | null; |
|
||||||
/** |
|
||||||
* Returns whether this variable has been defined or not. |
|
||||||
* |
|
||||||
* @return true if this variable has been defined, false otherwise |
|
||||||
*/ |
|
||||||
isDefined(): boolean; |
|
||||||
isBuildVariable(): boolean; |
|
||||||
isEnvironmentVariable(): boolean; |
|
||||||
} |
|
@ -1,91 +0,0 @@ |
|||||||
"use strict"; |
|
||||||
Object.defineProperty(exports, "__esModule", { value: true }); |
|
||||||
class Variable { |
|
||||||
constructor(name, nameRange, range, modifier, modifierRange, substitutionParameter, substitutionRange, defined, buildVariable, stringValue) { |
|
||||||
this.name = name; |
|
||||||
this.nameRange = nameRange; |
|
||||||
this.range = range; |
|
||||||
this.modifier = modifier; |
|
||||||
this.modifierRange = modifierRange; |
|
||||||
this.substitutionParameter = substitutionParameter; |
|
||||||
this.substitutionRange = substitutionRange; |
|
||||||
this.defined = defined; |
|
||||||
this.buildVariable = buildVariable; |
|
||||||
this.stringValue = stringValue; |
|
||||||
} |
|
||||||
toString() { |
|
||||||
return this.stringValue; |
|
||||||
} |
|
||||||
getName() { |
|
||||||
return this.name; |
|
||||||
} |
|
||||||
getNameRange() { |
|
||||||
return this.nameRange; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Returns the range of the entire variable. This includes the symbols for |
|
||||||
* the declaration of the variable such as the $, {, and } symbols. |
|
||||||
* |
|
||||||
* @return the range in the document that this variable encompasses in its |
|
||||||
* entirety |
|
||||||
*/ |
|
||||||
getRange() { |
|
||||||
return this.range; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Returns the modifier character that has been set for |
|
||||||
* specifying how this variable should be expanded and resolved. |
|
||||||
* If this variable is ${variable:+value} then the modifier |
|
||||||
* character is '+'. Will be the empty string if the variable is |
|
||||||
* declared as ${variable:}. Otherwise, will be null if this |
|
||||||
* variable will not use variable substitution at all (such as |
|
||||||
* ${variable} or $variable). |
|
||||||
* |
|
||||||
* @return this variable's modifier character, or the empty |
|
||||||
* string if it does not have one, or null if this |
|
||||||
* variable will not use variable substitution |
|
||||||
*/ |
|
||||||
getModifier() { |
|
||||||
return this.modifier; |
|
||||||
} |
|
||||||
getModifierRange() { |
|
||||||
return this.modifierRange; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Returns the parameter that will be used for substitution if |
|
||||||
* this variable uses modifiers to define how its value should be |
|
||||||
* resolved. If this variable is ${variable:+value} then the |
|
||||||
* substitution value will be 'value'. Will be the empty string |
|
||||||
* if the variable is declared as ${variable:+} or some other |
|
||||||
* variant where the only thing that follows the modifier |
|
||||||
* character (excluding considerations of escape characters and |
|
||||||
* so on) is the variable's closing bracket. May be null if this |
|
||||||
* variable does not have a modifier character defined (such as |
|
||||||
* ${variable} or $variable). |
|
||||||
* |
|
||||||
* @return this variable's substitution parameter, or the empty |
|
||||||
* string if it does not have one, or null if there is |
|
||||||
* not one defined |
|
||||||
*/ |
|
||||||
getSubstitutionParameter() { |
|
||||||
return this.substitutionParameter; |
|
||||||
} |
|
||||||
getSubstitutionRange() { |
|
||||||
return this.substitutionRange; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Returns whether this variable has been defined or not. |
|
||||||
* |
|
||||||
* @return true if this variable has been defined, false otherwise |
|
||||||
*/ |
|
||||||
isDefined() { |
|
||||||
return this.defined; |
|
||||||
} |
|
||||||
isBuildVariable() { |
|
||||||
return this.buildVariable === true; |
|
||||||
} |
|
||||||
isEnvironmentVariable() { |
|
||||||
return this.buildVariable === false; |
|
||||||
} |
|
||||||
} |
|
||||||
exports.Variable = Variable; |
|
@ -1,47 +0,0 @@ |
|||||||
{ |
|
||||||
"name": "dockerfile-ast", |
|
||||||
"description": "Parse a Dockerfile into an array of instructions and comments.", |
|
||||||
"keywords": [ |
|
||||||
"ast", |
|
||||||
"abstract", |
|
||||||
"docker", |
|
||||||
"dockerfile", |
|
||||||
"moby", |
|
||||||
"parse", |
|
||||||
"parser", |
|
||||||
"syntax", |
|
||||||
"tree" |
|
||||||
], |
|
||||||
"version": "0.1.0", |
|
||||||
"author": "Remy Suen", |
|
||||||
"license": "MIT", |
|
||||||
"bugs": "https://github.com/rcjsuen/dockerfile-ast/", |
|
||||||
"repository": { |
|
||||||
"type": "git", |
|
||||||
"url": "https://github.com/rcjsuen/dockerfile-ast.git" |
|
||||||
}, |
|
||||||
"engines": { |
|
||||||
"node": "*" |
|
||||||
}, |
|
||||||
"main": "lib/main.js", |
|
||||||
"typings": "./lib/main", |
|
||||||
"dependencies": { |
|
||||||
"vscode-languageserver-types": "^3.16.0" |
|
||||||
}, |
|
||||||
"devDependencies": { |
|
||||||
"@types/mocha": "^7.0.2", |
|
||||||
"@types/node": "^6.0.52", |
|
||||||
"mocha": "^7.0.2", |
|
||||||
"nyc": "^15.0.0", |
|
||||||
"typescript": "~3.7.3" |
|
||||||
}, |
|
||||||
"scripts": { |
|
||||||
"build": "tsc -p .", |
|
||||||
"prepublish": "tsc -p ./src", |
|
||||||
"watch": "tsc --watch -p .", |
|
||||||
"test": "mocha out/test out/test/instructions", |
|
||||||
"nyc": "nyc mocha out/test out/test/instructions", |
|
||||||
"nyc-ci": "nyc --cache false mocha out/test out/test/instructions", |
|
||||||
"coverage": "nyc report --reporter=text-lcov | coveralls" |
|
||||||
} |
|
||||||
} |
|
@ -1,584 +0,0 @@ |
|||||||
# Changelog |
|
||||||
All notable changes to this project will be documented in this file. |
|
||||||
|
|
||||||
## [0.2.2] - 2020-01-07 |
|
||||||
### Fixed |
|
||||||
- import all types from vscode-languageserver to prevent bundling issues ([#249](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/249)) |
|
||||||
|
|
||||||
## [0.2.1] - 2020-01-06 |
|
||||||
### Fixed |
|
||||||
- textDocument/semanticTokens |
|
||||||
- clearly declare that full document semantic tokens are supported in the returned server capabilities ([#248](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/248)) |
|
||||||
|
|
||||||
## [0.2.0] - 2020-12-25 |
|
||||||
### Added |
|
||||||
- textDocument/completion |
|
||||||
- CompletionItemTag is now supported when completing on the MAINTAINER keyword ([rcjsuen/dockerfile-language-service/#70](https://github.com/rcjsuen/dockerfile-language-service/issues/70)) |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- instructions with only an escape character as its argument should be flagged as not having any arguments ([rcjsuen/dockerfile-utils#83](https://github.com/rcjsuen/dockerfile-utils/issues/83)) |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- textDocument/semanticTokens |
|
||||||
- ENV instructions with blank space operators will no longer be assigned a semantic token ([rcjsuen/dockerfile-language-service#76](https://github.com/rcjsuen/dockerfile-language-service/issues/76)) |
|
||||||
- prevent infinite loop caused by invalid ENV instruction ([#246](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/246)) |
|
||||||
- replace deprecated `prepublish` script with `prepublishOnly` ([#111](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/111)) |
|
||||||
- fix server crash caused by the finalizing of the LSP 3.16 specification ([#247](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/247)) |
|
||||||
|
|
||||||
## [0.1.1] - 2020-07-13 |
|
||||||
### Fixed |
|
||||||
- textDocument/didChange |
|
||||||
- correctly consider an event with multiple changes at the beginning of a file ([#244](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/244)) |
|
||||||
|
|
||||||
## [0.1.0] - 2020-07-11 |
|
||||||
### Added |
|
||||||
- textDocument/definition |
|
||||||
- resolve build stage references to support definition navigation ([rcjsuen/dockerfile-language-service#67](https://github.com/rcjsuen/dockerfile-language-service/issues/67)) |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- warnings about the deprecated MAINTAINER instruction will now be specifically tagged as being a deprecation warning diagnostic ([#242](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/242)) |
|
||||||
- ARG and ENV instructions that span multiple lines with just a comment are now flagged as an error ([rcjsuen/dockerfile-utils#78](https://github.com/rcjsuen/dockerfile-utils/issues/78)) |
|
||||||
- use DiagnosticTag to indicate if a Diagnostic is informing the user about a deprecation or not([rcjsuen/dockerfile-utils#80](https://github.com/rcjsuen/dockerfile-utils/issues/80)) |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- textDocument/definition |
|
||||||
- build stages are no longer included as a link ([rcjsuen/dockerfile-language-service#68](https://github.com/rcjsuen/dockerfile-language-service/issues/68)) |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- correct ranges of linting errors if the error is on a multiline argument that is preceded by the escape character ([rcjsuen/dockerfile-utils#77](https://github.com/rcjsuen/dockerfile-utils/issues/77)) |
|
||||||
- fix linting error caused by whitespace followed after the escape character ([rcjsuen/dockerfile-utils#79](https://github.com/rcjsuen/dockerfile-utils/issues/79)) |
|
||||||
- textDocument/semanticTokens |
|
||||||
- allow embedded comments to immediately follow an ENV declaration ([rcjsuen/dockerfile-language-service#69](https://github.com/rcjsuen/dockerfile-language-service/issues/69)) |
|
||||||
- fix the semantic tokens calculation to allow flags to have options without a value and improved handling of multiline strings ([#239](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/239)) |
|
||||||
- fix builds so that Docker images are pushed to Docker Hub ([#243](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/243)) |
|
||||||
|
|
||||||
## [0.0.24] - 2020-04-23 |
|
||||||
### Fixed |
|
||||||
- textDocument/semanticTokens |
|
||||||
- improved support and parsing of strings and variables ([#239](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/239)) |
|
||||||
|
|
||||||
## [0.0.23] - 2020-04-03 |
|
||||||
### Added |
|
||||||
- textDocument/completion |
|
||||||
- support completion of the `syntax` parser directive ([rcjsuen/dockerfile-language-service#57](https://github.com/rcjsuen/dockerfile-language-service/issues/57)) |
|
||||||
- textDocument/documentSymbol |
|
||||||
- support multiple directives when calculating a Dockerfile's symbols ([rcjsuen/dockerfile-language-service#65](https://github.com/rcjsuen/dockerfile-language-service/issues/65)) |
|
||||||
- textDocument/hover |
|
||||||
- add hover support for the `syntax` parser directive ([rcjsuen/dockerfile-language-service#58](https://github.com/rcjsuen/dockerfile-language-service/issues/58)) |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- RUN instructions with only flags and no arguments will now be raised as an error ([rcjsuen/dockerfile-utils#76](https://github.com/rcjsuen/dockerfile-utils/issues/76)) |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- textDocument/hover |
|
||||||
- allow hovers to be displayed for instruction keywords that span multiple lines ([rcjsuen/dockerfile-language-service#59](https://github.com/rcjsuen/dockerfile-language-service/issues/59)) |
|
||||||
- correct hover resolution of a variable if it comes after a false comment in a multiline instruction ([rcjsuen/dockerfile-language-service#61](https://github.com/rcjsuen/dockerfile-language-service/issues/61)) |
|
||||||
- correct hover resolution of a variable that comes after an embedded comment with a trailing escape character in a multiline instruction ([rcjsuen/dockerfile-language-service#62](https://github.com/rcjsuen/dockerfile-language-service/issues/62)) |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- multiline instructions with empty newlines will no longer throw an error during validation ([rcjsuen/dockerfile-utils#71](https://github.com/rcjsuen/dockerfile-utils/issues/71)) |
|
||||||
- instruction keywords that span multiple lines will no longer be raised as an error ([rcjsuen/dockerfile-utils#72](https://github.com/rcjsuen/dockerfile-utils/issues/72)) |
|
||||||
- embedded comments with an empty continuation line will no longer be raised as an error ([rcjsuen/dockerfile-utils#73](https://github.com/rcjsuen/dockerfile-utils/issues/73)) |
|
||||||
- arguments that follow a non-leading `#` comment marker will no longer be dropped during validation ([rcjsuen/dockerfile-utils#75](https://github.com/rcjsuen/dockerfile-utils/issues/75)) |
|
||||||
- fix parsing of embedded comments in multiline instructions that have a trailing escape character ([rcjsuen/dockerfile-utils#74](https://github.com/rcjsuen/dockerfile-utils/issues/74)) |
|
||||||
- textDocument/semanticTokens |
|
||||||
- revamp to better handle strings, more tokens supported, and various fixes ([#239](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/239)) |
|
||||||
- textDocument/signatureHelp |
|
||||||
- use plain text instead of Markdown content for the signature label of the escape parser directive ([#64](https://github.com/rcjsuen/dockerfile-language-service/issues/64)) |
|
||||||
|
|
||||||
## [0.0.22] - 2020-02-12 |
|
||||||
### Added |
|
||||||
- textDocument/completion |
|
||||||
- support completing of tags for published images on the Docker Store ([rcjsuen/dockerfile-language-service#50](https://github.com/rcjsuen/dockerfile-language-service/issues/50)) |
|
||||||
- support completion of the `--platform` flag for FROMs introduced in Docker CE 18.04 ([rcjsuen/dockerfile-language-service#52](https://github.com/rcjsuen/dockerfile-language-service/issues/52)) |
|
||||||
- textDocument/hover |
|
||||||
- support hover documentation for the `--platform` flag for FROMs introduced in Docker CE 18.04 ([rcjsuen/dockerfile-language-service#53](https://github.com/rcjsuen/dockerfile-language-service/issues/53)) |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- add validation of FROM's `--platform` flag introduced in Docker CE 18.04 ([rcjsuen/dockerfile-utils#68](https://github.com/rcjsuen/dockerfile-utils/issues/68)) |
|
||||||
- `ValidationCode.UNKNOWN_FROM_FLAG` |
|
||||||
- warn if two escape parser directives are defined ([rcjsuen/dockerfile-utils#70](https://github.com/rcjsuen/dockerfile-utils/issues/70)) |
|
||||||
- textDocument/semanticTokens |
|
||||||
- experimental work-in-progress support to allow semantic tokens to be calculated and returned ([#239](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/239)) |
|
||||||
- as the language server protocol API is still in flux, the exact request parameters and response results may change |
|
||||||
- it is also possible that this request will not be fulfilled in a future release as a decision may be made to drop support for this |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- textDocument/formatting |
|
||||||
- do not calculate edits for lines that are already formatted correctly ([rcjsuen/dockerfile-utils#66](https://github.com/rcjsuen/dockerfile-utils/issues/66)) |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- allow paths to be quoted in WORKDIRs ([rcjsuen/dockerfile-utils#67](https://github.com/rcjsuen/dockerfile-utils/issues/67)) |
|
||||||
- allow an instruction with an argument on the last line to be parsed if it has no leading whitespace and has a length of one ([rcjsuen/dockerfile-utils#69](https://github.com/rcjsuen/dockerfile-utils/issues/69)) |
|
||||||
- textDocument/rangeFormatting |
|
||||||
- do not calculate edits for lines that are already formatted correctly ([rcjsuen/dockerfile-utils#66](https://github.com/rcjsuen/dockerfile-utils/issues/66)) |
|
||||||
|
|
||||||
## [0.0.21] - 2019-05-26 |
|
||||||
### Added |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- allow Bash syntax for variable modifiers in RUNs ([rcjsuen/dockerfile-utils#56](https://github.com/rcjsuen/dockerfile-utils/issues/56)) |
|
||||||
- warn if FROM has a variable for an image and it references nothing ([rcjsuen/dockerfile-utils#59](https://github.com/rcjsuen/dockerfile-utils/issues/59)) |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- textDocument/completion |
|
||||||
- corrected a small typo for VOLUME ([rcjsuen/dockerfile-language-service#47](https://github.com/rcjsuen/dockerfile-language-service/issues/47)) |
|
||||||
- textDocument/definition |
|
||||||
- only allow alphanumeric characters and underscores in variable names ([rcjsuen/dockerfile-language-service#49](https://github.com/rcjsuen/dockerfile-language-service/issues/49)) |
|
||||||
- textDocument/documentHighlight |
|
||||||
- only allow alphanumeric characters and underscores in variable names ([rcjsuen/dockerfile-language-service#49](https://github.com/rcjsuen/dockerfile-language-service/issues/49)) |
|
||||||
- textDocument/hover |
|
||||||
- corrected a small typo for VOLUME ([rcjsuen/dockerfile-language-service#47](https://github.com/rcjsuen/dockerfile-language-service/issues/47)) |
|
||||||
- only allow alphanumeric characters and underscores in variable names ([rcjsuen/dockerfile-language-service#49](https://github.com/rcjsuen/dockerfile-language-service/issues/49)) |
|
||||||
- textDocument/prepareRename |
|
||||||
- only allow alphanumeric characters and underscores in variable names ([rcjsuen/dockerfile-language-service#49](https://github.com/rcjsuen/dockerfile-language-service/issues/49)) |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- EXPOSE on a port with an ENV variable that references a valid ARG variable should not get flagged as an error ([#235](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/235)) |
|
||||||
- allow quoted ARG variables in EXPOSE ([rcjsuen/dockerfile-utils#58](https://github.com/rcjsuen/dockerfile-utils/issues/58)) |
|
||||||
- do not validate variable substitutions if found in RUN ([rcjsuen/dockerfile-utils#60](https://github.com/rcjsuen/dockerfile-utils/issues/60)) |
|
||||||
- textDocument/rename |
|
||||||
- only allow alphanumeric characters and underscores in variable names ([rcjsuen/dockerfile-language-service#49](https://github.com/rcjsuen/dockerfile-language-service/issues/49)) |
|
||||||
|
|
||||||
## [0.0.20] - 2019-01-01 |
|
||||||
### Added |
|
||||||
- textDocument/foldingRange |
|
||||||
- support folding of instructions that span multiple lines ([rcjsuen/dockerfile-language-service#43](https://github.com/rcjsuen/dockerfile-language-service/issues/43)) |
|
||||||
- textDocument/prepareRename |
|
||||||
- add support for determining whether something in a Dockerfile can be renamed or not ([#231](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/231)) |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- ignore invalid URIs from the client ([#232](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/232)) |
|
||||||
- textDocument/foldingRange |
|
||||||
- consider non-numeric values properly when checking the client's range limit for folding ranges ([#229](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/229)) |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- ignore variables when validating directories for ARGs and COPYs ([rcjsuen/dockerfile-utils#54](https://github.com/rcjsuen/dockerfile-utils/issues/54)) |
|
||||||
- textDocument/definition |
|
||||||
- allow build stages to be case insensitive when looking up its definition ([rcjsuen/dockerfile-language-service#41](https://github.com/rcjsuen/dockerfile-language-service/issues/41)) |
|
||||||
- textDocument/documentHighlight |
|
||||||
- allow build stages to be case insensitive when highlighting them ([rcjsuen/dockerfile-language-service#41](https://github.com/rcjsuen/dockerfile-language-service/issues/41)) |
|
||||||
- consider all build stages with the same name in FROMs when highlighting ([rcjsuen/dockerfile-language-service#42](https://github.com/rcjsuen/dockerfile-language-service/issues/42)) |
|
||||||
- textDocument/rename |
|
||||||
- allow build stages to be case insensitive when renaming them ([rcjsuen/dockerfile-language-service#41](https://github.com/rcjsuen/dockerfile-language-service/issues/41)) |
|
||||||
- consider all build stages with the same name in FROMs when renaming ([rcjsuen/dockerfile-language-service#42](https://github.com/rcjsuen/dockerfile-language-service/issues/42)) |
|
||||||
|
|
||||||
## [0.0.19] - 2018-08-22 |
|
||||||
### Added |
|
||||||
- textDocument/codeActions |
|
||||||
- return code action literals if the client supports it ([#225](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/225)) |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- add support for SCTP in EXPOSE instruction ([rcjsuen/dockerfile-utils#52](https://github.com/rcjsuen/dockerfile-utils/issues/52)) |
|
||||||
- warn if WORKDIR is not an absolute path ([#228](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/228)) |
|
||||||
- textDocument/foldingRange |
|
||||||
- add support for computing folding ranges in a Dockerfile ([#226](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/226)) |
|
||||||
|
|
||||||
### Changed |
|
||||||
- [upgraded the dependency of Mocha](https://github.com/mochajs/mocha/issues/2791) from 3.x to 5.x |
|
||||||
- versions prior to 4.x of Mocha dependended on Growl 1.9.2 which contained a [security vulnerability](https://github.com/tj/node-growl/issues/60) |
|
||||||
- as Mocha is a `devDependencies` module, there is no reason to believe that consumers of the `dockerfile-language-server-nodejs` module itself was affected by this vulnerability |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- textDocument/completion |
|
||||||
- send back deprecated items for MAINTAINER if the client supports it ([#224](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/224)) |
|
||||||
- textDocument/didChange |
|
||||||
- handle notifications that do not specify the range of the event ([#227](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/227)) |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- fix incorrect validation of ENV and LABEL instructions with many quoted properties on mulitple lines ([rcjsuen/dockerfile-utils#50](https://github.com/rcjsuen/dockerfile-utils/issues/50)) |
|
||||||
|
|
||||||
## [0.0.18] - 2018-06-30 |
|
||||||
### Added |
|
||||||
- documentLink/resolve |
|
||||||
- document links are now resolved in a two-step process ([#221](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/221)) |
|
||||||
- textDocument/completion |
|
||||||
- MAINTAINER instructions flagged as being deprecated ([rcjsuen/dockerfile-language-service#35](https://github.com/rcjsuen/dockerfile-language-service/issues/35)) |
|
||||||
- textDocument/documentSymbol |
|
||||||
- MAINTAINER instructions flagged as being deprecated ([#223](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/223)) |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- flag FROM instructions that refer to an invalid image digest in a private registry with a port as an error ([rcjsuen/dockerfile-utils#42](https://github.com/rcjsuen/dockerfile-utils/issues/42)) |
|
||||||
- flag variables that have an invalid modifier set ([rcjsuen/dockerfile-utils#38](https://github.com/rcjsuen/dockerfile-utils/issues/38)) |
|
||||||
- warn if ARG instruction does not define a name for the variable ([rcjsuen/dockerfile-utils#45](https://github.com/rcjsuen/dockerfile-utils/issues/45)) |
|
||||||
- flag incorrectly quoted arguments for ARG, ENV, and LABEL ([rcjsuen/dockerfile-utils#40](https://github.com/rcjsuen/dockerfile-utils/issues/40)) |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- textDocument/completion |
|
||||||
- image tag completion inserts extra text if word boundary is ambiguous ([rcjsuen/dockerfile-language-service#39](https://github.com/rcjsuen/dockerfile-language-service/issues/39)) |
|
||||||
- textDocument/hover |
|
||||||
- resolve variables to uninitialized ARGs with ARGs at the top of the Dockerfile if they exist ([rcjsuen/dockerfile-language-service#34](https://github.com/rcjsuen/dockerfile-language-service/issues/34)) |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- fix incorrect validation warning in ARG, ENV, and LABEL instructions caused by quotes being used in variable replacements ([rcjsuen/dockerfile-utils#36](https://github.com/rcjsuen/dockerfile-utils/issues/36)) |
|
||||||
- fix incorrect validation of tagged images caused by FROM referencing images in a private registry ([rcjsuen/dockerfile-utils#39](https://github.com/rcjsuen/dockerfile-utils/issues/39)) |
|
||||||
- allow variables to be used in a FROM's base image argument ([rcjsuen/dockerfile-utils#43](https://github.com/rcjsuen/dockerfile-utils/issues/43)) |
|
||||||
- handle ARG instructions with escaped newlines that lead to an EOF comment ([rcjsuen/dockerfile-utils#44](https://github.com/rcjsuen/dockerfile-utils/issues/44)) |
|
||||||
|
|
||||||
## [0.0.17] - 2018-04-16 |
|
||||||
### Added |
|
||||||
- support fulfillment of textDocument requests to the server even if textDocument/didOpen has not been sent for a file ([#215](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/215)) |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- do not flag FROM instructions that use variables with an error ([rcjsuen/dockerfile-utils#35](https://github.com/rcjsuen/dockerfile-utils/issues/35)) |
|
||||||
|
|
||||||
## [0.0.16] - 2018-04-14 |
|
||||||
### Fixed |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- fix validator to consider the instructionJSONInSingleQuotes setting ([#218](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/218)) |
|
||||||
|
|
||||||
## [0.0.15] - 2018-04-14 |
|
||||||
### Added |
|
||||||
- settings |
|
||||||
- docker.languageserver.diagnostics.instructionJSONInSingleQuotes? ([#217](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/217)) |
|
||||||
- value = ( "ignore" | "warning" | "error" ) |
|
||||||
- completionItem/resolve |
|
||||||
- use Markdown for a completion item's documentation field if the client supports it ([#207](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/207)) |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- warn if hyphens are being parsed as a unit of time in HEALTHCHECK duration flags ([rcjsuen/dockerfile-utils#24](https://github.com/rcjsuen/dockerfile-utils/issues/24)) |
|
||||||
- warn if two or more decimals found in a unit of time in HEALTHCHECK duration flags ([rcjsuen/dockerfile-utils#25](https://github.com/rcjsuen/dockerfile-utils/issues/25)) |
|
||||||
- warn if two hyphens are found in HEALTHCHECK duration flags ([rcjsuen/dockerfile-utils#26](https://github.com/rcjsuen/dockerfile-utils/issues/26)) |
|
||||||
- warn if instruction is written in JSON form incorrectly with single quotes ([rcjsuen/dockerfile-utils#28](https://github.com/rcjsuen/dockerfile-utils/issues/28)) |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- textDocument/didChange |
|
||||||
- apply received changes in a textDocument/didChange in the order given in the JSON result instead of trying to sort them and apply them backwards ([#216](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/216)) |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- clear diagnostics when server receives textDocument/didClose so that they do not linger in the client ([#214](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/214)) |
|
||||||
- fix incorrect validation error if a COPY uses JSON arguments and its last string argument is correctly defined as a folder ([#217](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/217)) |
|
||||||
- fix incorrect validation error if an ADD uses JSON arguments and its last string argument is correctly defined as a folder ([rcjsuen/dockerfile-utils#30](https://github.com/rcjsuen/dockerfile-utils/issues/30)) |
|
||||||
- skip validation of content after a JSON's closing bracket ([rcjsuen/dockerfile-utils#33](https://github.com/rcjsuen/dockerfile-utils/issues/33)) |
|
||||||
- fix validation of number of arguments for ADD and COPY instructions written in JSON ([rcjsuen/dockerfile-utils#34](https://github.com/rcjsuen/dockerfile-utils/issues/34)) |
|
||||||
|
|
||||||
## [0.0.14] - 2018-03-08 |
|
||||||
### Added |
|
||||||
- update to target version 3.6.0 of the Language Server Protocol specification |
|
||||||
- create dependency on the dockerfile-language-service module ([#205](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/205)) |
|
||||||
- add package-lock.json file to help ensure a consistent dependency tree ([#210](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/210)) |
|
||||||
- update documentation to state that ARG was introduced in Docker 1.9 ([rcjsuen/dockerfile-language-service#7](https://github.com/rcjsuen/dockerfile-language-service/issues/7)) |
|
||||||
- textDocument/codeAction |
|
||||||
- create docker.command.removeEmptyContinuationLine to remove empty continuation lines in instructions that span multiple lines ([#203](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/203)) |
|
||||||
- textDocument/documentLink |
|
||||||
- create links to hub.docker.com for base image names in FROM ([#204](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/204)) |
|
||||||
- textDocument/hover |
|
||||||
- inspect client's capabilities to decide what content format to use for hovers ([#209](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/209)) |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- flag HEALTHCHECK durations that include a hyphen as an error ([rcjsuen/dockerfile-utils#18](https://github.com/rcjsuen/dockerfile-utils/issues/18)) |
|
||||||
- warn if ADD has more than two arguments and its last argument is not a directory ([rcjsuen/dockerfile-utils#17](https://github.com/rcjsuen/dockerfile-utils/issues/17)) |
|
||||||
- warn if COPY has more than two arguments and its last argument is not a directory ([rcjsuen/dockerfile-utils#14](https://github.com/rcjsuen/dockerfile-utils/issues/14)) |
|
||||||
- warn if FROM's base image's digest is invalid ([rcjsuen/dockerfile-utils#15](https://github.com/rcjsuen/dockerfile-utils/issues/15)) |
|
||||||
- warn if FROM's base image's tag is invalid ([rcjsuen/dockerfile-utils#20](https://github.com/rcjsuen/dockerfile-utils/issues/20)) |
|
||||||
- workspace/applyEdit |
|
||||||
- use versioned edits if the client supports it via the documentChanges client capability ([#202](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/202)) |
|
||||||
|
|
||||||
### Changed |
|
||||||
- this module now depends on version 4.0.0 of the vscode-languageserver npm module |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- merge defined and default variables together when suggesting completion items ([#200](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/200)) |
|
||||||
- do not suggest variables from another build stage as a completion item ([#201](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/201)) |
|
||||||
- change documentation to state that STOPSIGNAL was added in Docker 1.9 instead of Docker 1.12 ([rcjsuen/dockerfile-language-service#6](https://github.com/rcjsuen/dockerfile-language-service/issues/6)) |
|
||||||
- ignore and return null for hover computations with an invalid position ([rcjsuen/dockerfile-language-service#22](https://github.com/rcjsuen/dockerfile-language-service/issues/22)) |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- allow decimal values for HEALTHCHECK duration flags ([rcjsuen/dockerfile-utils#19](https://github.com/rcjsuen/dockerfile-utils/issues/19)) |
|
||||||
- warn if STOPSIGNAL uses invalid variables for its argument ([rcjsuen/dockerfile-utils#11](https://github.com/rcjsuen/dockerfile-utils/issues/11)) |
|
||||||
- use a non-zero range for the diagnostic if FROM's base image's digest is the empty string ([rcjsuen/dockerfile-utils#21](https://github.com/rcjsuen/dockerfile-utils/issues/21)) |
|
||||||
- ignore multiple CMD, ENTRYPOINT, and HEALTHCHECK instructions in a Dockerfile if there is only ever one in a build stage ([rcjsuen/dockerfile-utils#22](https://github.com/rcjsuen/dockerfile-utils/issues/22)) |
|
||||||
- textDocument/signatureHelp |
|
||||||
- align active parameter amongst all displayed signatures for a FROM with a build stage name ([rcjsuen/dockerfile-language-service#8](https://github.com/rcjsuen/dockerfile-language-service/issues/8)) |
|
||||||
- workspace/configuration |
|
||||||
- update code to consider it as a formal API instead of a proposed API ([#211](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/211)) |
|
||||||
|
|
||||||
### Removed |
|
||||||
- remove document analysis and processing code and tests in favor of the dockerfile-language-service module ([#205](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/205)) |
|
||||||
|
|
||||||
## [0.0.13] - 2018-01-19 |
|
||||||
### Added |
|
||||||
- create dependency on the dockerfile-utils module ([#79](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/79)) |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- warn if COPY's --from flag is invalid ([#149](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/149)) |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- ignore ARG variables with no default values in an EXPOSE ([#199](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/199)) |
|
||||||
|
|
||||||
### Removed |
|
||||||
- remove validation code and tests in favor of the dockerfile-utils module ([#79](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/79)) |
|
||||||
|
|
||||||
## [0.0.12] - 2018-01-11 |
|
||||||
### Added |
|
||||||
- create dependency on the dockerfile-ast NPM module ([#196](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/196)) |
|
||||||
- textDocument/completion |
|
||||||
- documentation for ADD and COPY's --chown flag ([#181](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/181)) |
|
||||||
- textDocument/hover |
|
||||||
- ADD and COPY's --chown flag ([#181](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/181)) |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- prevent signature help from showing in a multiline instruction's embedded comment ([#195](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/195)) |
|
||||||
- publish the docker-langserver binary with \n line endings for OS X ([#198](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/198)) |
|
||||||
|
|
||||||
### Removed |
|
||||||
- remove Dockerfile parsing code in src/parser ([#196](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/196)) |
|
||||||
|
|
||||||
## [0.0.11] - 2017-11-15 |
|
||||||
### Added |
|
||||||
- create a Docker image to run the language server ([#189](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/189)) |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- prevent completion items from being displayed in comments ([#190](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/190)) |
|
||||||
- expand environment variables when validating an EXPOSE ([#192](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/192)) |
|
||||||
- ignore variables that are in a LABEL's single quoted value string ([#191](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/191)) |
|
||||||
- support environment variables that span multiple lines ([#193](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/193)) |
|
||||||
- ignore spaces that come after an environment variable ([#194](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/194)) |
|
||||||
|
|
||||||
## [0.0.10] - 2017-10-23 |
|
||||||
### Added |
|
||||||
- textDocument/codeAction |
|
||||||
- create docker.command.flagToChown to convert an unknown ADD or COPY flag to a --chown ([#187](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/187)) |
|
||||||
### Fixed |
|
||||||
- use a reasonable range for the diagnostic if an unknown flag has no name ([#186](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/186)) |
|
||||||
- specify a section name when sending a workspace/configuration request ([#182](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/182)) |
|
||||||
|
|
||||||
## [0.0.9] - 2017-10-14 |
|
||||||
### Added |
|
||||||
- settings |
|
||||||
- docker.languageserver.diagnostics.emptyContinuationLine? ([#177](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/177)) |
|
||||||
- value = ( "ignore" | "warning" | "error" ) |
|
||||||
- toggles the diagnostic severity if empty continuation lines are found |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- warn about empty continuation lines ([#177](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/177)) |
|
||||||
- warn if ADD does not have two arguments ([#185](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/185)) |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- allow parameters to be suggested even if an ARG has no variables defined ([#184](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/184)) |
|
||||||
- do not assume that clients support workspace/applyEdit ([#183](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/183)) |
|
||||||
- fix broken socket support ([#178](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/178)) |
|
||||||
|
|
||||||
## [0.0.8] - 2017-10-05 |
|
||||||
### Added |
|
||||||
- textDocument/codeAction |
|
||||||
- create commands for converting unknown HEALTHCHECK flags ([#172](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/172)) |
|
||||||
- docker.command.flagToHealthcheckInterval |
|
||||||
- docker.command.flagToHealthcheckRetries |
|
||||||
- docker.command.flagToHealthcheckStartPeriod |
|
||||||
- docker.command.flagToHealthcheckTimeout |
|
||||||
- create docker.command.flagToCopyFrom to convert an unknown COPY flag ([#171](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/171)) |
|
||||||
- textDocument/completion |
|
||||||
- HEALTHCHECK's CMD and NONE arguments ([#169](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/169)) |
|
||||||
- ADD and COPY's --chown flag ([#166](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/166)) |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- warn if HEALTHCHECK's argument is not CMD or NONE ([#173](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/173)) |
|
||||||
- warn if HEALTHCHECK has a flag but no arguments ([#174](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/174)) |
|
||||||
- validate --chown flag in ADD and COPY ([#166](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/166)) |
|
||||||
- textDocument/signatureHelp |
|
||||||
- update ADD's signature to support the new --chown flag ([#166](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/166)) |
|
||||||
- workspace/configuration |
|
||||||
- implemented support to allow validator settings to not be global ([#179](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/179)) |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- correct the documentation of HEALTHCHECK's --retries flag's completion item ([#170](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/170)) |
|
||||||
- show correct parameter in HEALTHCHECK's signature help if it has an escaped newline ([#175](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/175)) |
|
||||||
- show correct parameter in ENV and LABEL's signature help if it has an escaped newline ([#176](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/176)) |
|
||||||
|
|
||||||
## [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 |
|
||||||
### Added |
|
||||||
- textDocument/completion |
|
||||||
- suggest completion items even if the prefix string's case does not match ([#142](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/142)) |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- warn about duplicated build stage names ([#133](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/133)) |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- fix completion handling so that the escape parser directive is suggested in more cases ([#138](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/138)) |
|
||||||
- always use the first declaration of a variable for its definition ([#141](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/141)) |
|
||||||
- highlight ARG variables that get declared again ([#140](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/140)) |
|
||||||
|
|
||||||
## [0.0.5] - 2017-08-07 |
|
||||||
### Fixed |
|
||||||
- do not show arguments if snippets are not supported ([#136](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/136)) |
|
||||||
- show only one ARG completion item if snippets are not supported ([#137](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/137)) |
|
||||||
|
|
||||||
## [0.0.4] - 2017-08-06 |
|
||||||
### Fixed |
|
||||||
- created actual docker-langserver file instead of referencing server.js ([#134](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/134)) |
|
||||||
|
|
||||||
## [0.0.3] - 2017-08-06 |
|
||||||
### Added |
|
||||||
- created a docker-langserver binary for launching the server ([#134](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/134)) |
|
||||||
- textDocument/codeAction |
|
||||||
- created docker.command.convertToLowercase for directives not written in lowercase ([#128](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/128)) |
|
||||||
- textDocument/onTypeFormatting |
|
||||||
- format the next line if an escape character is inserted ([#130](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/130)) |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- validate the syntax of LABEL instructions ([#100](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/100)) |
|
||||||
- warn if invalid ONBUILD trigger instructions are used ([#117](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/117)) |
|
||||||
- warn if ENV/LABEL instructions have a blank name ([#122](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/122)) |
|
||||||
- EXPOSE |
|
||||||
- warn if an invalid protocol is specified ([#126](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/126)) |
|
||||||
- SHELL |
|
||||||
- check that SHELL instructions are written as a JSON array ([#92](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/92)) |
|
||||||
- warn if SHELL's JSON array is empty ([#122](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/122)) |
|
||||||
- workspace/executeCommand |
|
||||||
- handle docker.command.convertToLowercase and convert the string in the range to lowercase ([#128](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/128)) |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- fixed parsing of escaped whitespace values in ENV instructions ([#115](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/115)) |
|
||||||
- prevent undeclared variables from being suggested as completion items ([#118](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/118)) |
|
||||||
- prevent completion items from being suggested in multiline instructions ([#125](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/125)) |
|
||||||
- handle TCP and UDP in an EXPOSE instruction's argument ([#123](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/123)) |
|
||||||
- only search for parser directives at the top of a Dockerfile ([#129](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/129)) |
|
||||||
- fix handling of escape characters nested in an instruction ([#131](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/131)) |
|
||||||
|
|
||||||
## [0.0.2] - 2017-07-31 |
|
||||||
### Added |
|
||||||
- settings |
|
||||||
- docker.languageserver.diagnostics.instructionCmdMultiple? ([#81](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/81)) |
|
||||||
- value = ( "ignore" | "warning" | "error" ) |
|
||||||
- toggles the diagnostic severity if multiple CMD instructions are found in the Dockerfile |
|
||||||
- docker.languageserver.diagnostics.instructionEntrypointMultiple? ([#90](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/90)) |
|
||||||
- value = ( "ignore" | "warning" | "error" ) |
|
||||||
- toggles the diagnostic severity if multiple ENTRYPOINT instructions are found in the Dockerfile |
|
||||||
- docker.languageserver.diagnostics.instructionHealthcheckMultiple? ([#80](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/80)) |
|
||||||
- value = ( "ignore" | "warning" | "error" ) |
|
||||||
- toggles the diagnostic severity if multiple HEALTHCHECK instructions are found in the Dockerfile |
|
||||||
- textDocument/completion |
|
||||||
- suggest build stage names in a COPY instruction ([#44](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/44)) |
|
||||||
- add '=' as a trigger character |
|
||||||
- include the --start-period flag in HEALTHCHECK CMD items ([#78](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/78)) |
|
||||||
- HEALTHCHECK CMD flags ([#69](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/69), [#101](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/101)) |
|
||||||
- suggest $ variables ([#93](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/93)) |
|
||||||
- ARG and ENV variables |
|
||||||
- default Docker ARG variables |
|
||||||
- add '$' as a trigger character |
|
||||||
- textDocument/hover |
|
||||||
- HEALTHCHECK CMD flags ([#82](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/82), [#104](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/104)) |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- check the spelling of instruction flags ([#75](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/75)) |
|
||||||
- COPY's from |
|
||||||
- HEALTHCHECK's interval, retries, start-period, timeout |
|
||||||
- multiple instructions found when only one allowed |
|
||||||
- CMD ([#81](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/81)) |
|
||||||
- ENTRYPOINT ([#90](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/90)) |
|
||||||
- HEALTHCHECK ([#80](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/80)) |
|
||||||
- check that the same flag is not used twice ([#83](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/83)) |
|
||||||
- COPY's from |
|
||||||
- HEALTHCHECK's interval, retries, start-period, timeout |
|
||||||
- check that flags have a value defined ([#91](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/91)) |
|
||||||
- COPY's from |
|
||||||
- HEALTHCHECK's interval, retries, start-period, timeout |
|
||||||
- HEALTHCHECK |
|
||||||
- warn if arguments follow a HEALTHCHECK NONE ([#84](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/84)) |
|
||||||
- warn if the retries flag doesn't specify a number ([#85](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/85)) |
|
||||||
- warn if the retries flag is not a positive intger ([#89](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/89)) |
|
||||||
- warn if no arguments follow a HEALTHCHECK CMD ([#96](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/96)) |
|
||||||
- warn if duration flags are invalid ([#87](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/87)) |
|
||||||
- warn if duration flags do not specify a duration ([#86](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/86)) |
|
||||||
- warn if duration flags are too short ([#97](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/97)) |
|
||||||
- ONBUILD |
|
||||||
- trigger instruction not written in uppercase ([#102](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/102)) |
|
||||||
- create diagnostics for validating trigger instructions' content ([#112](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/112)) |
|
||||||
- created a CHANGELOG.md file to document the project's changes ([#77](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/77)) |
|
||||||
|
|
||||||
### Fixed |
|
||||||
- fixed a typo in completion items for WORKDIR ([#76](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/76)) |
|
||||||
- fixed a parsing problem with ENV variables and escaped characters ([#94](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/94)) |
|
||||||
- fixed CMD validation to not warn even if there are no arguments ([#98](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/98s)) |
|
||||||
- fixed code actions to return something if a diagnostic's code is a string and not a number ([#99](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/99)) |
|
||||||
- fixed hovers not working for ONBUILD triggers that are not written in uppercase ([#103](https://github.com/rcjsuen/dockerfile-language-server-nodejs/issues/103)) |
|
||||||
|
|
||||||
## 0.0.1 - 2017-07-16 |
|
||||||
### Added |
|
||||||
- textDocument/didChange |
|
||||||
- incremental document synchronization |
|
||||||
- textDocument/publishDiagnostics |
|
||||||
- instructions not written in uppercase |
|
||||||
- directives not written in lowercase |
|
||||||
- missing or incorrect number of expected of arguments to an instruction |
|
||||||
- invalid escape parser directive value |
|
||||||
- EXPOSE |
|
||||||
- invalid container port |
|
||||||
- FROM |
|
||||||
- no FROM instruction found |
|
||||||
- having a second argument not equal to the AS keyword |
|
||||||
- STOPSIGNAL |
|
||||||
- invalid stop signal definition |
|
||||||
- textDocument/codeAction |
|
||||||
- convert instruction to uppercase |
|
||||||
- remove extra argument to instruction |
|
||||||
- convert invalid escape directive to backslash |
|
||||||
- convert invalid escape directive to backtick |
|
||||||
- convert second argument of FROM to AS |
|
||||||
- textDocument/completion |
|
||||||
- snippets support |
|
||||||
- instructions |
|
||||||
- escaper parser directive |
|
||||||
- ONBUILD trigger instructions |
|
||||||
- completionItem/resolve |
|
||||||
- provide documentation information |
|
||||||
- textDocument/hover |
|
||||||
- instructions |
|
||||||
- escape parser directive |
|
||||||
- ONBUILD trigger instructions |
|
||||||
- ARG and ENV variables |
|
||||||
- textDocument/documentHighlight |
|
||||||
- ARG and ENV variables |
|
||||||
- FROM and COPY build stages |
|
||||||
- textDocument/rename |
|
||||||
- ARG and ENV variables |
|
||||||
- FROM and COPY build stages |
|
||||||
- textDocument/definition |
|
||||||
- ARG and ENV variables |
|
||||||
- FROM and COPY build stages |
|
||||||
- textDocument/documentSymbol |
|
||||||
- instructions |
|
||||||
- escape parser directive |
|
||||||
- textDocument/formatting |
|
||||||
- textDocument/rangeFormatting |
|
||||||
|
|
||||||
[Unreleased]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.2.2...HEAD |
|
||||||
[0.2.2]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.2.1...v0.2.2 |
|
||||||
[0.2.1]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.2.0...v0.2.1 |
|
||||||
[0.2.0]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.1.1...v0.2.0 |
|
||||||
[0.1.1]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.1.0...v0.1.1 |
|
||||||
[0.1.0]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.24...v0.1.0 |
|
||||||
[0.0.24]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.23...v0.0.24 |
|
||||||
[0.0.23]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.22...v0.0.23 |
|
||||||
[0.0.22]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.21...v0.0.22 |
|
||||||
[0.0.21]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.20...v0.0.21 |
|
||||||
[0.0.20]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.19...v0.0.20 |
|
||||||
[0.0.19]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.18...v0.0.19 |
|
||||||
[0.0.18]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.17...v0.0.18 |
|
||||||
[0.0.17]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.16...v0.0.17 |
|
||||||
[0.0.16]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.15...v0.0.16 |
|
||||||
[0.0.15]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.14...v0.0.15 |
|
||||||
[0.0.14]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.13...v0.0.14 |
|
||||||
[0.0.13]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.12...v0.0.13 |
|
||||||
[0.0.12]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.11...v0.0.12 |
|
||||||
[0.0.11]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.10...v0.0.11 |
|
||||||
[0.0.10]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.9...v0.0.10 |
|
||||||
[0.0.9]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.8...v0.0.9 |
|
||||||
[0.0.8]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.7...v0.0.8 |
|
||||||
[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 |
|
||||||
[0.0.5]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.4...v0.0.5 |
|
||||||
[0.0.4]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.3...v0.0.4 |
|
||||||
[0.0.3]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.2...v0.0.3 |
|
||||||
[0.0.2]: https://github.com/rcjsuen/dockerfile-language-server-nodejs/compare/v0.0.1...v0.0.2 |
|
@ -1,8 +0,0 @@ |
|||||||
FROM node:alpine |
|
||||||
COPY lib /docker-langserver/lib |
|
||||||
COPY bin /docker-langserver/bin |
|
||||||
COPY package.json /docker-langserver/package.json |
|
||||||
WORKDIR /docker-langserver/ |
|
||||||
RUN npm install --production && \ |
|
||||||
chmod +x /docker-langserver/bin/docker-langserver |
|
||||||
ENTRYPOINT [ "/docker-langserver/bin/docker-langserver" ] |
|
@ -1,22 +0,0 @@ |
|||||||
Copyright (c) 2017 Remy Suen |
|
||||||
|
|
||||||
MIT License |
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining |
|
||||||
a copy of this software and associated documentation files (the |
|
||||||
"Software"), to deal in the Software without restriction, including |
|
||||||
without limitation the rights to use, copy, modify, merge, publish, |
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to |
|
||||||
permit persons to whom the Software is furnished to do so, subject to |
|
||||||
the following conditions: |
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be |
|
||||||
included in all copies or substantial portions of the Software. |
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
@ -1,31 +0,0 @@ |
|||||||
The code in this repository was originally based off of open source |
|
||||||
code from the Microsoft/vscode-languageserver-node-example repository |
|
||||||
hosted on GitHub. |
|
||||||
|
|
||||||
https://github.com/Microsoft/vscode-languageserver-node-example |
|
||||||
|
|
||||||
The commit that this project was originally based off of is: 05aedee8564f11d59a759b654d06f24fdac4fa2f |
|
||||||
|
|
||||||
https://github.com/Microsoft/vscode-languageserver-node-example/commit/05aedee8564f11d59a759b654d06f24fdac4fa2f |
|
||||||
|
|
||||||
The original license of the code is attached below: |
|
||||||
|
|
||||||
----------------------------------- |
|
||||||
|
|
||||||
Copyright (c) Microsoft Corporation |
|
||||||
|
|
||||||
All rights reserved. |
|
||||||
|
|
||||||
MIT License |
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files |
|
||||||
(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, |
|
||||||
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do |
|
||||||
so, subject to the following conditions: |
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. |
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE |
|
||||||
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
@ -1,350 +0,0 @@ |
|||||||
# Dockerfile Language Server |
|
||||||
|
|
||||||
[](https://travis-ci.org/rcjsuen/dockerfile-language-server-nodejs) [](https://coveralls.io/github/rcjsuen/dockerfile-language-server-nodejs?branch=master) [](https://david-dm.org/rcjsuen/dockerfile-language-server-nodejs) [](https://opensource.org/licenses/MIT) |
|
||||||
|
|
||||||
This is a language server for Dockerfiles powered by Node.js written in TypeScript. |
|
||||||
To [install and run](#installation-instructions) this language server, you will need to have either [Node.js](https://nodejs.org/en/download/) or [Docker](https://www.docker.com/get-docker) installed on your computer. |
|
||||||
|
|
||||||
**Supported features:** |
|
||||||
- code actions |
|
||||||
- code completion |
|
||||||
- definition |
|
||||||
- diagnostics |
|
||||||
- document highlight |
|
||||||
- document links |
|
||||||
- document symbols |
|
||||||
- folding ranges |
|
||||||
- formatting |
|
||||||
- hovers |
|
||||||
- prepare rename |
|
||||||
- rename |
|
||||||
- semantic highlighting (experimental support for the upcoming LSP 3.16 specification) |
|
||||||
- signature help |
|
||||||
|
|
||||||
**Projects that use this language server:** |
|
||||||
- [vscode-docker](https://github.com/Microsoft/vscode-docker) |
|
||||||
- [atom-ide-docker](https://github.com/josa42/atom-ide-docker) |
|
||||||
- [Sourcegraph](https://sourcegraph.com/) |
|
||||||
- [Theia](https://theia-ide.org/) |
|
||||||
- [lsp-mode](https://emacs-lsp.github.io/lsp-mode/) |
|
||||||
|
|
||||||
This repository only contains the code necessary for launching a Dockerfile language server that conforms to the language server protocol. |
|
||||||
The actual code for parsing a Dockerfile and offering editor features such as code completion or hovers is not contained within this repository. |
|
||||||
|
|
||||||
The code for analyzing and processing a Dockerfile is contained in the following three libraries: |
|
||||||
- [dockerfile-ast](https://github.com/rcjsuen/dockerfile-ast) - parses a Dockerfile |
|
||||||
- [dockerfile-language-service](https://github.com/rcjsuen/dockerfile-language-service) - provides API functions for handling the different requests defined by the language server protocol |
|
||||||
- [dockerfile-utils](https://github.com/rcjsuen/dockerfile-utils) - validates and formats a Dockerfile, can be run from the CLI |
|
||||||
|
|
||||||
All of the language server protocol requests that help create a rich editing experience for the user is forwarded to the `dockerfile-language-service` library. |
|
||||||
You can test its features [right in the browser](https://rcjsuen.github.io/dockerfile-language-service/). |
|
||||||
This online editor is a very good representation of what is possible when this language server is connected to an editor that supports the language server protocol. |
|
||||||
|
|
||||||
## Development Instructions |
|
||||||
|
|
||||||
If you wish to build and compile this language server, you must first install [Node.js](https://nodejs.org/en/download/) if you have not already done so. |
|
||||||
After you have installed Node.js and cloned the repository with Git, you may now proceed to build and compile the language server with the following commands: |
|
||||||
|
|
||||||
``` |
|
||||||
npm install |
|
||||||
npm run build |
|
||||||
npm test |
|
||||||
``` |
|
||||||
|
|
||||||
If you are planning to change the code, use `npm run watch` to get the |
|
||||||
TypeScript files transpiled on-the-fly as they are modified. |
|
||||||
|
|
||||||
Once the code has finished compiling, you can connect a language server |
|
||||||
client to the server via Node IPC, stdio, or sockets. |
|
||||||
|
|
||||||
## Installation Instructions |
|
||||||
|
|
||||||
To install this language server onto your computer, please install the |
|
||||||
[dockerfile-language-server-nodejs npm module](https://www.npmjs.com/package/dockerfile-language-server-nodejs). |
|
||||||
The `-g` flag will install the npm module globally onto your computer. |
|
||||||
|
|
||||||
``` |
|
||||||
npm install -g dockerfile-language-server-nodejs |
|
||||||
``` |
|
||||||
|
|
||||||
After the installation has completed, you can start the language |
|
||||||
server with the `docker-langserver` binary. You should specify |
|
||||||
the desired method of communicating with the language server via one |
|
||||||
of the three arguments shown below. |
|
||||||
|
|
||||||
``` |
|
||||||
docker-langserver --node-ipc |
|
||||||
docker-langserver --stdio |
|
||||||
docker-langserver --socket=<port> |
|
||||||
``` |
|
||||||
|
|
||||||
### Docker Image |
|
||||||
The `docker-langserver` binary is also available as a Docker image under the name `rcjsuen/docker-langserver`. |
|
||||||
|
|
||||||
## Language Server Settings |
|
||||||
|
|
||||||
Clients may send a `workspace/didChangeConfiguration` notification to |
|
||||||
notify the server of settings changes. |
|
||||||
|
|
||||||
The settings object that will be included with the notification must conform |
|
||||||
to the following specification. |
|
||||||
|
|
||||||
```TypeScript |
|
||||||
interface Settings { |
|
||||||
docker: { |
|
||||||
languageserver: { |
|
||||||
diagnostics?: { |
|
||||||
// string values must be equal to "ignore", "warning", or "error" |
|
||||||
deprecatedMaintainer?: string, |
|
||||||
directiveCasing?: string, |
|
||||||
emptyContinuationLine?: string, |
|
||||||
instructionCasing?: string, |
|
||||||
instructionCmdMultiple?: string, |
|
||||||
instructionEntrypointMultiple?: string, |
|
||||||
instructionHealthcheckMultiple?: string, |
|
||||||
instructionJSONInSingleQuotes?: string |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
## Communicating with the Server |
|
||||||
### Node IPC |
|
||||||
|
|
||||||
With the `child_process` API, you can `fork()` a new Node.js process |
|
||||||
running the language server and communicate with it using `send(message)` |
|
||||||
and `on('message', ...)`. |
|
||||||
|
|
||||||
```TypeScript |
|
||||||
import * as child_process from "child_process"; |
|
||||||
|
|
||||||
let lspProcess = child_process.fork("out/src/server.js", [ "--node-ipc" ]); |
|
||||||
let messageId = 1; |
|
||||||
|
|
||||||
function send(method: string, params: object) { |
|
||||||
let message = { |
|
||||||
jsonrpc: "2.0", |
|
||||||
id: messageId++, |
|
||||||
method: method, |
|
||||||
params: params |
|
||||||
}; |
|
||||||
lspProcess.send(message); |
|
||||||
} |
|
||||||
|
|
||||||
function initialize() { |
|
||||||
send("initialize", { |
|
||||||
rootPath: process.cwd(), |
|
||||||
processId: process.pid, |
|
||||||
capabilities: { |
|
||||||
/* ... */ |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
lspProcess.on('message', function (json) { |
|
||||||
console.log(json); |
|
||||||
}); |
|
||||||
initialize(); |
|
||||||
``` |
|
||||||
|
|
||||||
### Standard Input/Output |
|
||||||
|
|
||||||
When writing directly to the process's stdin, the additional `Content-Length` |
|
||||||
header must be included. Similarly, when reading from the process's stdout, the |
|
||||||
header will be included in the response message. |
|
||||||
|
|
||||||
```TypeScript |
|
||||||
import * as child_process from "child_process"; |
|
||||||
|
|
||||||
let lspProcess = child_process.spawn("node", [ "out/src/server.js", "--stdio" ]); |
|
||||||
let messageId = 1; |
|
||||||
|
|
||||||
function send(method: string, params: object) { |
|
||||||
let message = { |
|
||||||
jsonrpc: "2.0", |
|
||||||
id: messageId++, |
|
||||||
method: method, |
|
||||||
params: params |
|
||||||
}; |
|
||||||
let json = JSON.stringify(message); |
|
||||||
let headers = "Content-Length: " + json.length + "\r\n\r\n"; |
|
||||||
lspProcess.stdin.write(headers, "ASCII"); |
|
||||||
lspProcess.stdin.write(json, "UTF-8"); |
|
||||||
} |
|
||||||
|
|
||||||
function initialize() { |
|
||||||
send("initialize", { |
|
||||||
rootPath: process.cwd(), |
|
||||||
processId: process.pid, |
|
||||||
capabilities: { |
|
||||||
/* ... */ |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
lspProcess.stdout.on("data", (message) => { |
|
||||||
// "Content-Length: ...\r\n\r\n\" will be included here |
|
||||||
console.log(message.toString()); |
|
||||||
}); |
|
||||||
|
|
||||||
initialize(); |
|
||||||
``` |
|
||||||
|
|
||||||
#### vscode-jsonrpc |
|
||||||
|
|
||||||
The `StreamMessageReader` and `StreamMessageWriter` classes from the |
|
||||||
`vscode-jsonrpc` module will handle the `Content-Length` headers for you so you |
|
||||||
only have to worry about the actual request and response. |
|
||||||
|
|
||||||
```TypeScript |
|
||||||
import * as child_process from "child_process"; |
|
||||||
import { StreamMessageReader, StreamMessageWriter } from "vscode-jsonrpc"; |
|
||||||
|
|
||||||
let lspProcess = child_process.spawn("node", [ "out/src/server.js", "--stdio" ]); |
|
||||||
let messageId = 1; |
|
||||||
|
|
||||||
const reader = new StreamMessageReader(lspProcess.stdout); |
|
||||||
const writer = new StreamMessageWriter(lspProcess.stdin); |
|
||||||
|
|
||||||
function send(method: string, params: object) { |
|
||||||
let message = { |
|
||||||
jsonrpc: "2.0", |
|
||||||
id: messageId++, |
|
||||||
method: method, |
|
||||||
params: params |
|
||||||
}; |
|
||||||
writer.write(message); |
|
||||||
} |
|
||||||
|
|
||||||
function initialize() { |
|
||||||
send("initialize", { |
|
||||||
rootPath: process.cwd(), |
|
||||||
processId: process.pid, |
|
||||||
capabilities: { |
|
||||||
/* ... */ |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
reader.listen((data) => { |
|
||||||
console.log(data); |
|
||||||
}) |
|
||||||
|
|
||||||
initialize(); |
|
||||||
``` |
|
||||||
|
|
||||||
### Sockets |
|
||||||
|
|
||||||
To communicate with the langauge server via a socket, a port must be opened |
|
||||||
up first to listen for incoming connections. After the port is opened, the |
|
||||||
language server may be started and told to connect to the specified port. |
|
||||||
Messages can then be read from and written to the socket. |
|
||||||
|
|
||||||
Just like when trying to communicate to the server using |
|
||||||
[stdio](#standard-inputoutput), the `Content-Length` headers must be written |
|
||||||
and parsed explicitly. |
|
||||||
|
|
||||||
```TypeScript |
|
||||||
import * as net from "net" |
|
||||||
import * as child_process from "child_process" |
|
||||||
|
|
||||||
let messageId = 1; |
|
||||||
|
|
||||||
function send(socket: net.Socket, method: string, params: object) { |
|
||||||
let message = { |
|
||||||
jsonrpc: "2.0", |
|
||||||
id: messageId++, |
|
||||||
method: method, |
|
||||||
params: params |
|
||||||
}; |
|
||||||
let json = JSON.stringify(message) + "\n"; |
|
||||||
let headers = "Content-Length: " + json.length + "\r\n\r\n"; |
|
||||||
socket.write(headers, "ASCII"); |
|
||||||
socket.write(json, "UTF-8"); |
|
||||||
} |
|
||||||
|
|
||||||
function initialize(socket: net.Socket) { |
|
||||||
send(socket, "initialize", { |
|
||||||
rootPath: process.cwd(), |
|
||||||
processId: process.pid, |
|
||||||
capabilities: { |
|
||||||
textDocument: { |
|
||||||
/* ... */ |
|
||||||
}, |
|
||||||
workspace: { |
|
||||||
/* ... */ |
|
||||||
} |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
const server = net.createServer((socket: net.Socket) => { |
|
||||||
server.close(); |
|
||||||
socket.on("data", (message) => { |
|
||||||
// "Content-Length: ...\r\n\r\n\" will be included here |
|
||||||
console.log(message.toString()); |
|
||||||
}); |
|
||||||
initialize(socket); |
|
||||||
}); |
|
||||||
|
|
||||||
server.listen(3000, () => { |
|
||||||
child_process.spawn("node", [ "out/src/server.js", "--socket=3000" ]); |
|
||||||
}); |
|
||||||
``` |
|
||||||
|
|
||||||
#### vscode-jsonrpc |
|
||||||
|
|
||||||
The `SocketMessageReader` and `SocketMessageWriter` classes from the |
|
||||||
`vscode-jsonrpc` module will handle the `Content-Length` headers for you so you |
|
||||||
only have to worry about the actual request and response. |
|
||||||
|
|
||||||
```TypeScript |
|
||||||
import * as net from "net" |
|
||||||
import * as child_process from "child_process" |
|
||||||
import { SocketMessageReader, SocketMessageWriter } from "vscode-jsonrpc"; |
|
||||||
|
|
||||||
let messageId = 1; |
|
||||||
let reader: SocketMessageReader = null; |
|
||||||
let writer: SocketMessageWriter = null; |
|
||||||
|
|
||||||
function send(method: string, params: object) { |
|
||||||
let message = { |
|
||||||
jsonrpc: "2.0", |
|
||||||
id: messageId++, |
|
||||||
method: method, |
|
||||||
params: params |
|
||||||
}; |
|
||||||
writer.write(message); |
|
||||||
} |
|
||||||
|
|
||||||
function initialize() { |
|
||||||
send("initialize", { |
|
||||||
rootPath: process.cwd(), |
|
||||||
processId: process.pid, |
|
||||||
capabilities: { |
|
||||||
textDocument: { |
|
||||||
/* ... */ |
|
||||||
}, |
|
||||||
workspace: { |
|
||||||
/* ... */ |
|
||||||
} |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
const server = net.createServer((socket: net.Socket) => { |
|
||||||
server.close(); |
|
||||||
reader = new SocketMessageReader(socket); |
|
||||||
reader.listen((data) => { |
|
||||||
console.log(data); |
|
||||||
}); |
|
||||||
writer = new SocketMessageWriter(socket); |
|
||||||
initialize(); |
|
||||||
}); |
|
||||||
|
|
||||||
server.listen(3000, () => { |
|
||||||
child_process.spawn("node", [ "out/src/server.js", "--socket=3000" ]); |
|
||||||
}); |
|
||||||
``` |
|
Binary file not shown.
@ -1,598 +0,0 @@ |
|||||||
/* -------------------------------------------------------------------------------------------- |
|
||||||
* 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 }); |
|
||||||
const fs = require("fs"); |
|
||||||
const node_1 = require("vscode-languageserver/node"); |
|
||||||
const files_1 = require("vscode-languageserver/lib/node/files"); |
|
||||||
const dockerfile_utils_1 = require("dockerfile-utils"); |
|
||||||
const dockerfile_language_service_1 = require("dockerfile-language-service"); |
|
||||||
/** |
|
||||||
* The settings to use for the validator if the client doesn't support |
|
||||||
* workspace/configuration requests. |
|
||||||
*/ |
|
||||||
let validatorSettings = null; |
|
||||||
/** |
|
||||||
* The validator settings that correspond to an individual file retrieved via |
|
||||||
* the workspace/configuration request. |
|
||||||
*/ |
|
||||||
let validatorConfigurations = new Map(); |
|
||||||
let connection = node_1.createConnection(node_1.ProposedFeatures.all); |
|
||||||
let service = dockerfile_language_service_1.DockerfileLanguageServiceFactory.createLanguageService(); |
|
||||||
service.setLogger({ |
|
||||||
log(message) { |
|
||||||
connection.console.log(message); |
|
||||||
} |
|
||||||
}); |
|
||||||
/** |
|
||||||
* Whether the client supports the workspace/applyEdit request. |
|
||||||
*/ |
|
||||||
let applyEditSupport = false; |
|
||||||
/** |
|
||||||
* Whether the client supports the workspace/configuration request. |
|
||||||
*/ |
|
||||||
let configurationSupport = false; |
|
||||||
let documentChangesSupport = false; |
|
||||||
let codeActionQuickFixSupport = false; |
|
||||||
let documents = {}; |
|
||||||
/** |
|
||||||
* Retrieves a text document for the file located at the given URI |
|
||||||
* string. |
|
||||||
* |
|
||||||
* @param uri the URI of the interested file, must be defined and not |
|
||||||
* null |
|
||||||
* @return the text document for the file, or null if no file exists |
|
||||||
* at the given location |
|
||||||
*/ |
|
||||||
function getDocument(uri) { |
|
||||||
if (documents[uri]) { |
|
||||||
return Promise.resolve(documents[uri]); |
|
||||||
} |
|
||||||
return new Promise((resolve, reject) => { |
|
||||||
let file = files_1.uriToFilePath(uri); |
|
||||||
if (file === undefined) { |
|
||||||
resolve(null); |
|
||||||
} |
|
||||||
else { |
|
||||||
fs.exists(file, (exists) => { |
|
||||||
if (exists) { |
|
||||||
fs.readFile(file, (err, data) => { |
|
||||||
resolve(node_1.TextDocument.create(uri, "dockerfile", 1, data.toString())); |
|
||||||
}); |
|
||||||
} |
|
||||||
else { |
|
||||||
resolve(null); |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
function supportsDeprecatedItems(capabilities) { |
|
||||||
return capabilities.textDocument |
|
||||||
&& capabilities.textDocument.completion |
|
||||||
&& capabilities.textDocument.completion.completionItem |
|
||||||
&& capabilities.textDocument.completion.completionItem.deprecatedSupport; |
|
||||||
} |
|
||||||
function supportsSnippets(capabilities) { |
|
||||||
return capabilities.textDocument |
|
||||||
&& capabilities.textDocument.completion |
|
||||||
&& capabilities.textDocument.completion.completionItem |
|
||||||
&& capabilities.textDocument.completion.completionItem.snippetSupport; |
|
||||||
} |
|
||||||
function supportsCodeActionQuickFixes(capabilities) { |
|
||||||
let values = capabilities.textDocument |
|
||||||
&& capabilities.textDocument.codeAction |
|
||||||
&& capabilities.textDocument.codeAction.codeActionLiteralSupport |
|
||||||
&& capabilities.textDocument.codeAction.codeActionLiteralSupport.codeActionKind |
|
||||||
&& capabilities.textDocument.codeAction.codeActionLiteralSupport.codeActionKind.valueSet; |
|
||||||
if (values === null || values === undefined) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
for (let value of values) { |
|
||||||
if (value === node_1.CodeActionKind.QuickFix) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Gets the MarkupKind[] that the client supports for the |
|
||||||
* documentation field of a CompletionItem. |
|
||||||
* |
|
||||||
* @return the supported MarkupKind[], may be null or undefined |
|
||||||
*/ |
|
||||||
function getCompletionItemDocumentationFormat(capabilities) { |
|
||||||
return capabilities.textDocument |
|
||||||
&& capabilities.textDocument.completion |
|
||||||
&& capabilities.textDocument.completion.completionItem |
|
||||||
&& capabilities.textDocument.completion.completionItem.documentationFormat; |
|
||||||
} |
|
||||||
function getHoverContentFormat(capabilities) { |
|
||||||
return capabilities.textDocument |
|
||||||
&& capabilities.textDocument.hover |
|
||||||
&& capabilities.textDocument.hover.contentFormat; |
|
||||||
} |
|
||||||
function getLineFoldingOnly(capabilities) { |
|
||||||
return capabilities.textDocument |
|
||||||
&& capabilities.textDocument.foldingRange |
|
||||||
&& capabilities.textDocument.foldingRange.lineFoldingOnly; |
|
||||||
} |
|
||||||
function getRangeLimit(capabilities) { |
|
||||||
let rangeLimit = capabilities.textDocument |
|
||||||
&& capabilities.textDocument.foldingRange |
|
||||||
&& capabilities.textDocument.foldingRange.rangeLimit; |
|
||||||
if (rangeLimit === null || rangeLimit === undefined || typeof rangeLimit === "boolean" || isNaN(rangeLimit)) { |
|
||||||
rangeLimit = Number.MAX_VALUE; |
|
||||||
} |
|
||||||
else if (typeof rangeLimit !== "number") { |
|
||||||
// isNaN === false and not a number, must be a string number, convert it
|
|
||||||
rangeLimit = Number(rangeLimit); |
|
||||||
} |
|
||||||
return rangeLimit; |
|
||||||
} |
|
||||||
function setServiceCapabilities(capabilities) { |
|
||||||
service.setCapabilities({ |
|
||||||
completion: { |
|
||||||
completionItem: { |
|
||||||
deprecatedSupport: supportsDeprecatedItems(capabilities), |
|
||||||
documentationFormat: getCompletionItemDocumentationFormat(capabilities), |
|
||||||
snippetSupport: supportsSnippets(capabilities) |
|
||||||
} |
|
||||||
}, |
|
||||||
hover: { |
|
||||||
contentFormat: getHoverContentFormat(capabilities) |
|
||||||
}, |
|
||||||
foldingRange: { |
|
||||||
lineFoldingOnly: getLineFoldingOnly(capabilities), |
|
||||||
rangeLimit: getRangeLimit(capabilities) |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
connection.onInitialized(() => { |
|
||||||
if (configurationSupport) { |
|
||||||
// listen for notification changes if the client supports workspace/configuration
|
|
||||||
connection.client.register(node_1.DidChangeConfigurationNotification.type); |
|
||||||
} |
|
||||||
}); |
|
||||||
connection.onInitialize((params) => { |
|
||||||
setServiceCapabilities(params.capabilities); |
|
||||||
applyEditSupport = params.capabilities.workspace && params.capabilities.workspace.applyEdit === true; |
|
||||||
documentChangesSupport = params.capabilities.workspace && params.capabilities.workspace.workspaceEdit && params.capabilities.workspace.workspaceEdit.documentChanges === true; |
|
||||||
configurationSupport = params.capabilities.workspace && params.capabilities.workspace.configuration === true; |
|
||||||
const renamePrepareSupport = params.capabilities.textDocument && params.capabilities.textDocument.rename && params.capabilities.textDocument.rename.prepareSupport === true; |
|
||||||
const semanticTokensSupport = params.capabilities.textDocument && params.capabilities.textDocument.semanticTokens; |
|
||||||
codeActionQuickFixSupport = supportsCodeActionQuickFixes(params.capabilities); |
|
||||||
return { |
|
||||||
capabilities: { |
|
||||||
textDocumentSync: node_1.TextDocumentSyncKind.Incremental, |
|
||||||
codeActionProvider: applyEditSupport, |
|
||||||
completionProvider: { |
|
||||||
resolveProvider: true, |
|
||||||
triggerCharacters: [ |
|
||||||
'=', |
|
||||||
' ', |
|
||||||
'$', |
|
||||||
'-', |
|
||||||
] |
|
||||||
}, |
|
||||||
executeCommandProvider: applyEditSupport ? { |
|
||||||
commands: [ |
|
||||||
dockerfile_language_service_1.CommandIds.LOWERCASE, |
|
||||||
dockerfile_language_service_1.CommandIds.UPPERCASE, |
|
||||||
dockerfile_language_service_1.CommandIds.EXTRA_ARGUMENT, |
|
||||||
dockerfile_language_service_1.CommandIds.DIRECTIVE_TO_BACKSLASH, |
|
||||||
dockerfile_language_service_1.CommandIds.DIRECTIVE_TO_BACKTICK, |
|
||||||
dockerfile_language_service_1.CommandIds.FLAG_TO_CHOWN, |
|
||||||
dockerfile_language_service_1.CommandIds.FLAG_TO_COPY_FROM, |
|
||||||
dockerfile_language_service_1.CommandIds.FLAG_TO_HEALTHCHECK_INTERVAL, |
|
||||||
dockerfile_language_service_1.CommandIds.FLAG_TO_HEALTHCHECK_RETRIES, |
|
||||||
dockerfile_language_service_1.CommandIds.FLAG_TO_HEALTHCHECK_START_PERIOD, |
|
||||||
dockerfile_language_service_1.CommandIds.FLAG_TO_HEALTHCHECK_TIMEOUT, |
|
||||||
dockerfile_language_service_1.CommandIds.CONVERT_TO_AS, |
|
||||||
dockerfile_language_service_1.CommandIds.REMOVE_EMPTY_CONTINUATION_LINE |
|
||||||
] |
|
||||||
} : undefined, |
|
||||||
documentFormattingProvider: true, |
|
||||||
documentRangeFormattingProvider: true, |
|
||||||
documentOnTypeFormattingProvider: { |
|
||||||
firstTriggerCharacter: '\\', |
|
||||||
moreTriggerCharacter: ['`'] |
|
||||||
}, |
|
||||||
hoverProvider: true, |
|
||||||
documentSymbolProvider: true, |
|
||||||
documentHighlightProvider: true, |
|
||||||
renameProvider: renamePrepareSupport ? { |
|
||||||
prepareProvider: true |
|
||||||
} : true, |
|
||||||
definitionProvider: true, |
|
||||||
signatureHelpProvider: { |
|
||||||
triggerCharacters: [ |
|
||||||
'-', |
|
||||||
'[', |
|
||||||
',', |
|
||||||
' ', |
|
||||||
'=' |
|
||||||
] |
|
||||||
}, |
|
||||||
documentLinkProvider: { |
|
||||||
resolveProvider: true |
|
||||||
}, |
|
||||||
semanticTokensProvider: semanticTokensSupport ? { |
|
||||||
full: { |
|
||||||
delta: false |
|
||||||
}, |
|
||||||
legend: { |
|
||||||
tokenTypes: [ |
|
||||||
node_1.SemanticTokenTypes.keyword, |
|
||||||
node_1.SemanticTokenTypes.comment, |
|
||||||
node_1.SemanticTokenTypes.parameter, |
|
||||||
node_1.SemanticTokenTypes.property, |
|
||||||
node_1.SemanticTokenTypes.namespace, |
|
||||||
node_1.SemanticTokenTypes.class, |
|
||||||
node_1.SemanticTokenTypes.macro, |
|
||||||
node_1.SemanticTokenTypes.string, |
|
||||||
node_1.SemanticTokenTypes.variable, |
|
||||||
node_1.SemanticTokenTypes.operator |
|
||||||
], |
|
||||||
tokenModifiers: [ |
|
||||||
node_1.SemanticTokenModifiers.declaration, |
|
||||||
node_1.SemanticTokenModifiers.definition, |
|
||||||
node_1.SemanticTokenModifiers.deprecated |
|
||||||
] |
|
||||||
} |
|
||||||
} : undefined, |
|
||||||
foldingRangeProvider: true |
|
||||||
} |
|
||||||
}; |
|
||||||
}); |
|
||||||
function convertValidatorConfiguration(config) { |
|
||||||
let deprecatedMaintainer = dockerfile_utils_1.ValidationSeverity.WARNING; |
|
||||||
let directiveCasing = dockerfile_utils_1.ValidationSeverity.WARNING; |
|
||||||
let emptyContinuationLine = dockerfile_utils_1.ValidationSeverity.WARNING; |
|
||||||
let instructionCasing = dockerfile_utils_1.ValidationSeverity.WARNING; |
|
||||||
let instructionCmdMultiple = dockerfile_utils_1.ValidationSeverity.WARNING; |
|
||||||
let instructionEntrypointMultiple = dockerfile_utils_1.ValidationSeverity.WARNING; |
|
||||||
let instructionHealthcheckMultiple = dockerfile_utils_1.ValidationSeverity.WARNING; |
|
||||||
let instructionJSONInSingleQuotes = dockerfile_utils_1.ValidationSeverity.WARNING; |
|
||||||
let instructionWorkdirRelative = dockerfile_utils_1.ValidationSeverity.WARNING; |
|
||||||
if (config) { |
|
||||||
deprecatedMaintainer = getSeverity(config.deprecatedMaintainer); |
|
||||||
directiveCasing = getSeverity(config.directiveCasing); |
|
||||||
emptyContinuationLine = getSeverity(config.emptyContinuationLine); |
|
||||||
instructionCasing = getSeverity(config.instructionCasing); |
|
||||||
instructionCmdMultiple = getSeverity(config.instructionCmdMultiple); |
|
||||||
instructionEntrypointMultiple = getSeverity(config.instructionEntrypointMultiple); |
|
||||||
instructionHealthcheckMultiple = getSeverity(config.instructionHealthcheckMultiple); |
|
||||||
instructionJSONInSingleQuotes = getSeverity(config.instructionJSONInSingleQuotes); |
|
||||||
instructionWorkdirRelative = getSeverity(config.instructionWorkdirRelative); |
|
||||||
} |
|
||||||
return { |
|
||||||
deprecatedMaintainer, |
|
||||||
directiveCasing, |
|
||||||
emptyContinuationLine, |
|
||||||
instructionCasing, |
|
||||||
instructionCmdMultiple, |
|
||||||
instructionEntrypointMultiple, |
|
||||||
instructionHealthcheckMultiple, |
|
||||||
instructionJSONInSingleQuotes, |
|
||||||
instructionWorkdirRelative |
|
||||||
}; |
|
||||||
} |
|
||||||
function validateTextDocument(textDocument) { |
|
||||||
if (configurationSupport) { |
|
||||||
getConfiguration(textDocument.uri).then((config) => { |
|
||||||
const fileSettings = convertValidatorConfiguration(config); |
|
||||||
const diagnostics = service.validate(textDocument.getText(), fileSettings); |
|
||||||
connection.sendDiagnostics({ uri: textDocument.uri, diagnostics }); |
|
||||||
}); |
|
||||||
} |
|
||||||
else { |
|
||||||
const diagnostics = service.validate(textDocument.getText(), validatorSettings); |
|
||||||
connection.sendDiagnostics({ uri: textDocument.uri, diagnostics }); |
|
||||||
} |
|
||||||
} |
|
||||||
function getSeverity(severity) { |
|
||||||
switch (severity) { |
|
||||||
case "ignore": |
|
||||||
return dockerfile_utils_1.ValidationSeverity.IGNORE; |
|
||||||
case "warning": |
|
||||||
return dockerfile_utils_1.ValidationSeverity.WARNING; |
|
||||||
case "error": |
|
||||||
return dockerfile_utils_1.ValidationSeverity.ERROR; |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
/** |
|
||||||
* Gets the validation configuration that pertains to the specified resource. |
|
||||||
* |
|
||||||
* @param resource the interested resource |
|
||||||
* @return the configuration to use to validate the interested resource |
|
||||||
*/ |
|
||||||
function getConfiguration(resource) { |
|
||||||
let result = validatorConfigurations.get(resource); |
|
||||||
if (!result) { |
|
||||||
result = connection.workspace.getConfiguration({ section: "docker.languageserver.diagnostics", scopeUri: resource }); |
|
||||||
validatorConfigurations.set(resource, result); |
|
||||||
} |
|
||||||
return result; |
|
||||||
} |
|
||||||
// listen for notifications when the client's configuration has changed
|
|
||||||
connection.onNotification(node_1.DidChangeConfigurationNotification.type, () => { |
|
||||||
refreshConfigurations(); |
|
||||||
}); |
|
||||||
/** |
|
||||||
* Wipes and reloads the internal cache of validator configurations. |
|
||||||
*/ |
|
||||||
function refreshConfigurations() { |
|
||||||
// store all the URIs that need to be refreshed
|
|
||||||
const settingsRequest = []; |
|
||||||
for (let uri in documents) { |
|
||||||
settingsRequest.push({ section: "docker.languageserver.diagnostics", scopeUri: uri }); |
|
||||||
} |
|
||||||
// clear the cache
|
|
||||||
validatorConfigurations.clear(); |
|
||||||
// ask the workspace for the configurations
|
|
||||||
connection.workspace.getConfiguration(settingsRequest).then((values) => { |
|
||||||
const toRevalidate = []; |
|
||||||
for (let i = 0; i < values.length; i++) { |
|
||||||
const resource = settingsRequest[i].scopeUri; |
|
||||||
// a value might have been stored already, use it instead and ignore this one if so
|
|
||||||
if (values[i] && !validatorConfigurations.has(resource)) { |
|
||||||
validatorConfigurations.set(resource, Promise.resolve(values[i])); |
|
||||||
toRevalidate.push(resource); |
|
||||||
} |
|
||||||
} |
|
||||||
for (const resource of toRevalidate) { |
|
||||||
validateTextDocument(documents[resource]); |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
connection.onDidChangeConfiguration((change) => { |
|
||||||
if (configurationSupport) { |
|
||||||
refreshConfigurations(); |
|
||||||
} |
|
||||||
else { |
|
||||||
let settings = change.settings; |
|
||||||
if (settings.docker && settings.docker.languageserver && settings.docker.languageserver.diagnostics) { |
|
||||||
validatorSettings = convertValidatorConfiguration(settings.docker.languageserver.diagnostics); |
|
||||||
} |
|
||||||
else { |
|
||||||
validatorSettings = convertValidatorConfiguration(null); |
|
||||||
} |
|
||||||
// validate all the documents again
|
|
||||||
Object.keys(documents).forEach((key) => { |
|
||||||
validateTextDocument(documents[key]); |
|
||||||
}); |
|
||||||
} |
|
||||||
}); |
|
||||||
connection.onCompletion((textDocumentPosition) => { |
|
||||||
return getDocument(textDocumentPosition.textDocument.uri).then((document) => { |
|
||||||
if (document) { |
|
||||||
return service.computeCompletionItems(document.getText(), textDocumentPosition.position); |
|
||||||
} |
|
||||||
return null; |
|
||||||
}); |
|
||||||
}); |
|
||||||
connection.onSignatureHelp((textDocumentPosition) => { |
|
||||||
return getDocument(textDocumentPosition.textDocument.uri).then((document) => { |
|
||||||
if (document !== null) { |
|
||||||
return service.computeSignatureHelp(document.getText(), textDocumentPosition.position); |
|
||||||
} |
|
||||||
return { |
|
||||||
signatures: [], |
|
||||||
activeSignature: null, |
|
||||||
activeParameter: null, |
|
||||||
}; |
|
||||||
}); |
|
||||||
}); |
|
||||||
connection.onCompletionResolve((item) => { |
|
||||||
return service.resolveCompletionItem(item); |
|
||||||
}); |
|
||||||
connection.onHover((textDocumentPosition) => { |
|
||||||
return getDocument(textDocumentPosition.textDocument.uri).then((document) => { |
|
||||||
if (document) { |
|
||||||
return service.computeHover(document.getText(), textDocumentPosition.position); |
|
||||||
} |
|
||||||
return null; |
|
||||||
}); |
|
||||||
}); |
|
||||||
connection.onDocumentHighlight((textDocumentPosition) => { |
|
||||||
return getDocument(textDocumentPosition.textDocument.uri).then((document) => { |
|
||||||
if (document) { |
|
||||||
return service.computeHighlightRanges(document.getText(), textDocumentPosition.position); |
|
||||||
} |
|
||||||
return []; |
|
||||||
}); |
|
||||||
}); |
|
||||||
connection.onCodeAction((codeActionParams) => { |
|
||||||
if (applyEditSupport && codeActionParams.context.diagnostics.length > 0) { |
|
||||||
let commands = service.computeCodeActions(codeActionParams.textDocument, codeActionParams.range, codeActionParams.context); |
|
||||||
if (codeActionQuickFixSupport) { |
|
||||||
return getDocument(codeActionParams.textDocument.uri).then((document) => { |
|
||||||
let codeActions = []; |
|
||||||
for (let command of commands) { |
|
||||||
let codeAction = { |
|
||||||
title: command.title, |
|
||||||
kind: node_1.CodeActionKind.QuickFix |
|
||||||
}; |
|
||||||
let edit = computeWorkspaceEdit(codeActionParams.textDocument.uri, document, command.command, command.arguments); |
|
||||||
if (edit) { |
|
||||||
codeAction.edit = edit; |
|
||||||
} |
|
||||||
codeActions.push(codeAction); |
|
||||||
} |
|
||||||
return codeActions; |
|
||||||
}); |
|
||||||
} |
|
||||||
return commands; |
|
||||||
} |
|
||||||
return []; |
|
||||||
}); |
|
||||||
function computeWorkspaceEdit(uri, document, command, args) { |
|
||||||
let edits = service.computeCommandEdits(document.getText(), command, args); |
|
||||||
if (edits) { |
|
||||||
if (documentChangesSupport) { |
|
||||||
let identifier = node_1.VersionedTextDocumentIdentifier.create(uri, document.version); |
|
||||||
return { |
|
||||||
documentChanges: [ |
|
||||||
node_1.TextDocumentEdit.create(identifier, edits) |
|
||||||
] |
|
||||||
}; |
|
||||||
} |
|
||||||
else { |
|
||||||
return { |
|
||||||
changes: { |
|
||||||
[uri]: edits |
|
||||||
} |
|
||||||
}; |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
connection.onExecuteCommand((params) => { |
|
||||||
if (applyEditSupport) { |
|
||||||
let uri = params.arguments[0]; |
|
||||||
getDocument(uri).then((document) => { |
|
||||||
if (document) { |
|
||||||
let workspaceEdit = computeWorkspaceEdit(uri, document, params.command, params.arguments); |
|
||||||
if (workspaceEdit) { |
|
||||||
connection.workspace.applyEdit(workspaceEdit); |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
}); |
|
||||||
} |
|
||||||
}); |
|
||||||
connection.onDefinition((textDocumentPosition) => { |
|
||||||
return getDocument(textDocumentPosition.textDocument.uri).then((document) => { |
|
||||||
if (document) { |
|
||||||
return service.computeDefinition(textDocumentPosition.textDocument, document.getText(), textDocumentPosition.position); |
|
||||||
} |
|
||||||
return null; |
|
||||||
}); |
|
||||||
}); |
|
||||||
connection.onRenameRequest((params) => { |
|
||||||
return getDocument(params.textDocument.uri).then((document) => { |
|
||||||
if (document) { |
|
||||||
let edits = service.computeRename(params.textDocument, document.getText(), params.position, params.newName); |
|
||||||
return { |
|
||||||
changes: { |
|
||||||
[params.textDocument.uri]: edits |
|
||||||
} |
|
||||||
}; |
|
||||||
} |
|
||||||
return null; |
|
||||||
}); |
|
||||||
}); |
|
||||||
connection.onPrepareRename((params) => { |
|
||||||
return getDocument(params.textDocument.uri).then((document) => { |
|
||||||
if (document) { |
|
||||||
return service.prepareRename(document.getText(), params.position); |
|
||||||
} |
|
||||||
return null; |
|
||||||
}); |
|
||||||
}); |
|
||||||
connection.onDocumentSymbol((documentSymbolParams) => { |
|
||||||
return getDocument(documentSymbolParams.textDocument.uri).then((document) => { |
|
||||||
if (document) { |
|
||||||
return service.computeSymbols(documentSymbolParams.textDocument, document.getText()); |
|
||||||
} |
|
||||||
return []; |
|
||||||
}); |
|
||||||
}); |
|
||||||
connection.onDocumentFormatting((documentFormattingParams) => { |
|
||||||
return getDocument(documentFormattingParams.textDocument.uri).then((document) => { |
|
||||||
if (document) { |
|
||||||
return service.format(document.getText(), documentFormattingParams.options); |
|
||||||
} |
|
||||||
return []; |
|
||||||
}); |
|
||||||
}); |
|
||||||
connection.onDocumentRangeFormatting((rangeFormattingParams) => { |
|
||||||
return getDocument(rangeFormattingParams.textDocument.uri).then((document) => { |
|
||||||
if (document) { |
|
||||||
return service.formatRange(document.getText(), rangeFormattingParams.range, rangeFormattingParams.options); |
|
||||||
} |
|
||||||
return []; |
|
||||||
}); |
|
||||||
}); |
|
||||||
connection.onDocumentOnTypeFormatting((onTypeFormattingParams) => { |
|
||||||
return getDocument(onTypeFormattingParams.textDocument.uri).then((document) => { |
|
||||||
if (document) { |
|
||||||
return service.formatOnType(document.getText(), onTypeFormattingParams.position, onTypeFormattingParams.ch, onTypeFormattingParams.options); |
|
||||||
} |
|
||||||
return []; |
|
||||||
}); |
|
||||||
}); |
|
||||||
connection.onDocumentLinks((documentLinkParams) => { |
|
||||||
return getDocument(documentLinkParams.textDocument.uri).then((document) => { |
|
||||||
if (document) { |
|
||||||
return service.computeLinks(document.getText()); |
|
||||||
} |
|
||||||
return []; |
|
||||||
}); |
|
||||||
}); |
|
||||||
connection.onDocumentLinkResolve((documentLink) => { |
|
||||||
return service.resolveLink(documentLink); |
|
||||||
}); |
|
||||||
connection.onFoldingRanges((foldingRangeParams) => { |
|
||||||
return getDocument(foldingRangeParams.textDocument.uri).then((document) => { |
|
||||||
if (document) { |
|
||||||
return service.computeFoldingRanges(document.getText()); |
|
||||||
} |
|
||||||
return []; |
|
||||||
}); |
|
||||||
}); |
|
||||||
connection.onDidOpenTextDocument((didOpenTextDocumentParams) => { |
|
||||||
let document = node_1.TextDocument.create(didOpenTextDocumentParams.textDocument.uri, didOpenTextDocumentParams.textDocument.languageId, didOpenTextDocumentParams.textDocument.version, didOpenTextDocumentParams.textDocument.text); |
|
||||||
documents[didOpenTextDocumentParams.textDocument.uri] = document; |
|
||||||
validateTextDocument(document); |
|
||||||
}); |
|
||||||
connection.languages.semanticTokens.on((semanticTokenParams) => { |
|
||||||
return getDocument(semanticTokenParams.textDocument.uri).then((document) => { |
|
||||||
if (document) { |
|
||||||
return service.computeSemanticTokens(document.getText()); |
|
||||||
} |
|
||||||
return { |
|
||||||
data: [] |
|
||||||
}; |
|
||||||
}); |
|
||||||
}); |
|
||||||
connection.onDidChangeTextDocument((didChangeTextDocumentParams) => { |
|
||||||
let document = documents[didChangeTextDocumentParams.textDocument.uri]; |
|
||||||
let buffer = document.getText(); |
|
||||||
let content = buffer; |
|
||||||
let changes = didChangeTextDocumentParams.contentChanges; |
|
||||||
for (let i = 0; i < changes.length; i++) { |
|
||||||
const change = changes[i]; |
|
||||||
if (!change.range && !change.rangeLength) { |
|
||||||
// no ranges defined, the text is the entire document then
|
|
||||||
buffer = change.text; |
|
||||||
document = node_1.TextDocument.create(didChangeTextDocumentParams.textDocument.uri, document.languageId, didChangeTextDocumentParams.textDocument.version, buffer); |
|
||||||
break; |
|
||||||
} |
|
||||||
let offset = document.offsetAt(change.range.start); |
|
||||||
let end = null; |
|
||||||
if (change.range.end) { |
|
||||||
end = document.offsetAt(change.range.end); |
|
||||||
} |
|
||||||
else { |
|
||||||
end = offset + change.rangeLength; |
|
||||||
} |
|
||||||
buffer = buffer.substring(0, offset) + change.text + buffer.substring(end); |
|
||||||
document = node_1.TextDocument.create(didChangeTextDocumentParams.textDocument.uri, document.languageId, didChangeTextDocumentParams.textDocument.version, buffer); |
|
||||||
} |
|
||||||
documents[didChangeTextDocumentParams.textDocument.uri] = document; |
|
||||||
if (content !== buffer) { |
|
||||||
validateTextDocument(document); |
|
||||||
} |
|
||||||
}); |
|
||||||
connection.onDidCloseTextDocument((didCloseTextDocumentParams) => { |
|
||||||
validatorConfigurations.delete(didCloseTextDocumentParams.textDocument.uri); |
|
||||||
connection.sendDiagnostics({ uri: didCloseTextDocumentParams.textDocument.uri, diagnostics: [] }); |
|
||||||
delete documents[didCloseTextDocumentParams.textDocument.uri]; |
|
||||||
}); |
|
||||||
// setup complete, start listening for a client connection
|
|
||||||
connection.listen(); |
|
@ -1,46 +0,0 @@ |
|||||||
{ |
|
||||||
"name": "dockerfile-language-server-nodejs", |
|
||||||
"description": "A language server for Dockerfiles powered by NodeJS, TypeScript, and VSCode technologies.", |
|
||||||
"keywords": [ |
|
||||||
"language", |
|
||||||
"server", |
|
||||||
"docker", |
|
||||||
"dockerfile", |
|
||||||
"moby" |
|
||||||
], |
|
||||||
"version": "0.2.2", |
|
||||||
"author": "Remy Suen", |
|
||||||
"license": "MIT", |
|
||||||
"bugs": "https://github.com/rcjsuen/dockerfile-language-server-nodejs/", |
|
||||||
"repository": { |
|
||||||
"type": "git", |
|
||||||
"url": "https://github.com/rcjsuen/dockerfile-language-server-nodejs.git" |
|
||||||
}, |
|
||||||
"engines": { |
|
||||||
"node": "*" |
|
||||||
}, |
|
||||||
"dependencies": { |
|
||||||
"dockerfile-language-service": "0.1.1", |
|
||||||
"dockerfile-utils": "0.1.1", |
|
||||||
"vscode-languageserver": "^7.0.0" |
|
||||||
}, |
|
||||||
"devDependencies": { |
|
||||||
"@types/mocha": "^7.0.2", |
|
||||||
"@types/node": "^6.0.52", |
|
||||||
"mocha": "^7.0.2", |
|
||||||
"typescript": "^4.1.3", |
|
||||||
"nyc": "^15.0.0" |
|
||||||
}, |
|
||||||
"bin": { |
|
||||||
"docker-langserver": "./bin/docker-langserver" |
|
||||||
}, |
|
||||||
"scripts": { |
|
||||||
"build": "tsc -p .", |
|
||||||
"prepublishOnly": "tsc -p ./src", |
|
||||||
"watch": "tsc --watch -p .", |
|
||||||
"test": "mocha out/test", |
|
||||||
"nyc": "nyc mocha out/test", |
|
||||||
"nyc-ci": "nyc --cache false mocha out/test", |
|
||||||
"coverage": "nyc report --reporter=text-lcov | coveralls" |
|
||||||
} |
|
||||||
} |
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue