diff --git a/src/components.json b/src/components.json index 7dfe6d098d..6a6246c4be 100644 --- a/src/components.json +++ b/src/components.json @@ -383,6 +383,10 @@ "title": "Docker", "owner": "JustinBeckwith" }, + "dotenv": { + "title": "Dotenv (.env)", + "owner": "DmitrySharabin" + }, "dot": { "title": "DOT (Graphviz)", "owner": "RunDevelopment" diff --git a/src/languages/dotenv.js b/src/languages/dotenv.js new file mode 100644 index 0000000000..aa6ce87307 --- /dev/null +++ b/src/languages/dotenv.js @@ -0,0 +1,98 @@ +/** @type {LanguageProto<'dotenv'>} */ +export default { + id: 'dotenv', + optional: 'bash', + grammar () { + /** + * @param {RegExp} prefix + * @returns {Array} + */ + const commonPatterns = prefix => { + return [ + { + pattern: RegExp( + prefix.source + + /(?:-?[1-9]\d*|0)(?:\\.\d+)?(?=\s*\}|\s[^}]+$|\s*$|"$)/.source + ), + alias: 'number', + }, + { + pattern: RegExp(prefix.source + /(?:false|true)(?=\s*\}|\s[^}]+$|\s*$)/.source), + alias: 'boolean', + }, + { + // Ignore leading and trailing whitespace characters + pattern: RegExp(prefix.source + /\S[^}]*?\S(?=\s*\})/.source), + alias: 'string', + }, + ]; + }; + + // Based on https://dotenvx.com/docs/env-file + return { + 'comment': + /(?:^|(?<=[\s"'`]))#(?![^\n"'`]*["'`])[^\r\n \t]*(?:[ \t]+[^\r\n \t]+)*[ \t]*/, + 'keyword': /^export(?=\s)/m, + 'key': { + // Allow bare keys (without values) + pattern: /(?<=^[ \t]*)[a-z_]\w*(?=[ \t]*(?:=|$))/im, + alias: 'constant', + }, + 'value': [ + { + pattern: /(?<==\s*)(?:-?[1-9]\d*|0)(?:\.\d+)?(?=\s*$)/, + alias: 'number', + }, + { + pattern: /(?<==\s*)(?:false|true)(?=\s*$)/, + alias: 'boolean', + }, + { + pattern: + /(?<==\s*)(?:(['"`])(?:\\[\s\S]|(?!\1)[^\\])*?\1|\S(?:.*?\S)?)(?=\s*$|\s+#.*$)/m, + alias: 'string', + inside: { + 'command-substitution': { + // Command substitution is disabled in strings enclosed in "'" (single quotes) and "`" (backticks) + pattern: /(?