From 132755aaed3114e08e0aa800567d44a42f606291 Mon Sep 17 00:00:00 2001 From: Johannes Rappen Date: Wed, 1 Jun 2022 01:43:33 +0200 Subject: [PATCH] [JSON] Rewrite syntax MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Using inheritance split up `JSON.sublime-syntax` into: - `JSON.sublime-syntax` with `scope:source.json` - `JSONC.sublime-syntax` with `scope:source.json.jsonc` - `JSON5.sublime-syntax` with `scope:source.json.json5` - `JSON_dotNET.sublime-syntax` with `scope:source.json.json-dotnet` - Add many more file extensions for `JSON` & `JSONC`: - add doc links to extensions where applicable as a reference to be able to more quickly verify that they (still) use said syntax flavor - JSON: - Make use of newer syntax features including those only available in `version: 2` syntaxes - Make use of `variables` (with optimizations provided by @deathaxe and regex patterns provided by @Thom1729) - Context names now more closely match the naming scheme of other (recently re-written) default syntaxes - (correctly formatted) JSON code can now be prettified or minified via the context menu or the command palette. JSON code can optionally be auto-prettified on pre save events. - highlight leading, trailing & multiple commas as invalid - only allow exactly one structure (object, array) or value (constant, number, string) at top level (thanks to @keith-hall) - links (`meta.link.inet`) and email addresses (`meta.link.email`) are scoped the same as in Markdown (thanks to @deathaxe) - JSONC: - highlight some files by default as `JSONC` (as decided by @jskinner in sublimehq/Packages#285) - highlight leading & multiple commas as invalid, trailing as valid - scope empty block comments as such - support syntax based folding of ST4131+, compare sublimehq/Packages#3291 - JSON5: - explicitly pos numbers, hexadecimal ints, Infinity and NaN - single quoted strings - more escape chars for strings - ECMA identifierName as object keys (regexes thanks to @Thom1729) - scoped as plain unquoted strings (thanks to @Thom1729) - support string interpolation (thanks to @deathaxe) - line continuation in strings (with tests thanks to @keith-hall) - JSON.NET: - support requested by @keith-hall, built with feedback from @michaelblyons - Objects: - Highlighting speed improvements for empty objects (thanks to @FichteFoll) - Make `mapping.*` contexts more modular - Arrays: - Highlighting speed improvements for empty arrays (thanks to @FichteFoll) - Numbers: - Correctly scope number signs with `constant.numeric.sign` instead of `keyword.operator.arithmetic` - Significantly improve number highlighting (thanks to @deathaxe) - Completions: - completions have been added for language constants, including kind info and details (with links to docs) - `null`, `false`, `true` for JSON - `Infinity` and `NaN` for JSON5 - Settings: - a `default_extension` is now set for all JSON flavors - Symbol index: - with an object structure at the top-level, only top-level keys within now show up in the index (including tests for symbols and syntax) - Tests: - test files now test the base scope - Significantly extend tests to cover more parts of the syntaxes - Split original test file into logical parts - Add indentation tests for: - `json`, `json5` & `jsonc` - `mapping` (objects), `sequence` (arrays) - Add symbols tests for: - top-level keys of object structures (thanks to deathaxe) - languages: `json`, `json5` & `jsonc` - Fix tests for `meta.mapping meta.mapping.*` - Leave `JSON` headers in `Markdown` as `json` only, but split up fenced code blocks into `json`, `json5` & `jsonc` to behave similarly to `GitHub Flavored Markdown` BREAKING CHANGES: - JSON does not have values that can be set via an inline calculation with the help of operators, but only simple number values. Scopes for number signs have changed from being `keyword.operator.arithmetic` to `constant.numeric.sign`. Color scheme authors should add this, should it be missing. - The `JSON.sublime-syntax` now marks comments as `invalid`, third party plugin authors should instead target `JSONC.sublime-syntax` to keep the user experience as-is. - Indexed symbols (i.e. top-level keys in JSON object structures) are scoped as `source.json meta.mapping.key - (meta.mapping.value meta.mapping.key | meta.sequence.list meta.mapping.key)`. Color scheme authors should add special highlighting to differentiate them from other keys. - fix sublimehq/Packages#285 - address sublimehq/Packages#421 (thanks to @FichteFoll) - address sublimehq/Packages#481 to remove incompatible regex patterns according to @wbond - address sublimehq/Packages#757 to fix line comments for `JSONC` (thanks to @keith-hall) - address sublimehq/Packages#2430 using sort-order (as requested by @deathaxe) - address sublimehq/Packages#2711 with regards to `constant.language.null` vs. `constant.language.empty` (thanks to @FichteFoll) - address sublimehq/Packages#2852 to fix scopes of curly braces & square brackets in `JSON` (thanks to @Thom1729) - address sublimehq/Packages#3228 to fix `punctuation.separator` scopes, compare sublimehq/Packages#3270 - address sublimehq/sublime_text#3154 and add symbol tests Co-authored-by: Ashwin Shenoy Co-authored-by: Jack Cherng Co-authored-by: Janos Wortmann Co-authored-by: Jon Skinner Co-authored-by: FichteFoll Co-authored-by: Keith Hall Co-authored-by: Michael B. Lyons Co-authored-by: Rafał Chłodnicki Co-authored-by: Thomas Smith Co-authored-by: Will Bond Co-authored-by: deathaxe --- HTML/syntax_test_html.html | 8 +- JSON/.python-version | 1 + JSON/Comments - JSON5.tmPreferences | 25 + JSON/Comments - JSONC.tmPreferences | 25 + JSON/Comments.tmPreferences | 31 - JSON/Context.sublime-menu | 29 + JSON/Default.sublime-commands | 29 + JSON/Default.sublime-keymap | 131 ++-- JSON/Fold.tmPreferences | 27 - JSON/Folding Rules - JSON.tmPreferences | 27 + JSON/Folding Rules - JSON5.tmPreferences | 31 + JSON/Folding Rules - JSONC.tmPreferences | 31 + .../Folding Rules - JSON_dotNET.tmPreferences | 27 + JSON/JSON.sublime-completions | 27 + JSON/JSON.sublime-settings | 13 + JSON/JSON.sublime-syntax | 603 ++++++++++++++---- JSON/JSON5.sublime-completions | 48 ++ JSON/JSON5.sublime-settings | 10 + JSON/JSON5.sublime-syntax | 255 ++++++++ JSON/JSONC.sublime-settings | 10 + JSON/JSONC.sublime-syntax | 136 ++++ JSON/JSON_dotNET.sublime-syntax | 106 +++ JSON/Main.sublime-menu | 130 ++++ JSON/Symbol List.tmPreferences | 14 + JSON/main.py | 18 + JSON/src/__init__.py | 9 + JSON/src/json_prettify.py | 217 +++++++ JSON/src/jsonc_prettify.py | 140 ++++ JSON/syntax_test_json.json | 123 ---- Markdown/Markdown.sublime-syntax | 42 +- Markdown/tests/syntax_test_markdown.md | 21 + Perl/Perl.sublime-syntax | 46 ++ Perl/syntax_test_perl.pl | 32 +- 33 files changed, 2048 insertions(+), 374 deletions(-) create mode 100644 JSON/.python-version create mode 100644 JSON/Comments - JSON5.tmPreferences create mode 100644 JSON/Comments - JSONC.tmPreferences delete mode 100644 JSON/Comments.tmPreferences create mode 100644 JSON/Context.sublime-menu create mode 100644 JSON/Default.sublime-commands delete mode 100644 JSON/Fold.tmPreferences create mode 100644 JSON/Folding Rules - JSON.tmPreferences create mode 100644 JSON/Folding Rules - JSON5.tmPreferences create mode 100644 JSON/Folding Rules - JSONC.tmPreferences create mode 100644 JSON/Folding Rules - JSON_dotNET.tmPreferences create mode 100644 JSON/JSON.sublime-completions create mode 100644 JSON/JSON.sublime-settings create mode 100644 JSON/JSON5.sublime-completions create mode 100644 JSON/JSON5.sublime-settings create mode 100644 JSON/JSON5.sublime-syntax create mode 100644 JSON/JSONC.sublime-settings create mode 100644 JSON/JSONC.sublime-syntax create mode 100644 JSON/JSON_dotNET.sublime-syntax create mode 100644 JSON/Main.sublime-menu create mode 100644 JSON/Symbol List.tmPreferences create mode 100644 JSON/main.py create mode 100644 JSON/src/__init__.py create mode 100644 JSON/src/json_prettify.py create mode 100644 JSON/src/jsonc_prettify.py delete mode 100644 JSON/syntax_test_json.json diff --git a/HTML/syntax_test_html.html b/HTML/syntax_test_html.html index 9c1539aa100..2d2aedcd40e 100644 --- a/HTML/syntax_test_html.html +++ b/HTML/syntax_test_html.html @@ -127,23 +127,23 @@ diff --git a/JSON/.python-version b/JSON/.python-version new file mode 100644 index 00000000000..cc1923a40b1 --- /dev/null +++ b/JSON/.python-version @@ -0,0 +1 @@ +3.8 diff --git a/JSON/Comments - JSON5.tmPreferences b/JSON/Comments - JSON5.tmPreferences new file mode 100644 index 00000000000..75aac0ef338 --- /dev/null +++ b/JSON/Comments - JSON5.tmPreferences @@ -0,0 +1,25 @@ + + + + scope + source.json.json5 + settings + + shellVariables + + + nameTM_COMMENT_START + value// + + + nameTM_COMMENT_START_2 + value/* + + + nameTM_COMMENT_END_2 + value*/ + + + + + diff --git a/JSON/Comments - JSONC.tmPreferences b/JSON/Comments - JSONC.tmPreferences new file mode 100644 index 00000000000..1ee8dd7e2af --- /dev/null +++ b/JSON/Comments - JSONC.tmPreferences @@ -0,0 +1,25 @@ + + + + scope + source.json.jsonc + settings + + shellVariables + + + nameTM_COMMENT_START + value// + + + nameTM_COMMENT_START_2 + value/* + + + nameTM_COMMENT_END_2 + value*/ + + + + + diff --git a/JSON/Comments.tmPreferences b/JSON/Comments.tmPreferences deleted file mode 100644 index d9695e9cf24..00000000000 --- a/JSON/Comments.tmPreferences +++ /dev/null @@ -1,31 +0,0 @@ - - - - scope - source.json - settings - - shellVariables - - - name - TM_COMMENT_START - value - // - - - name - TM_COMMENT_START_2 - value - /* - - - name - TM_COMMENT_END_2 - value - */ - - - - - diff --git a/JSON/Context.sublime-menu b/JSON/Context.sublime-menu new file mode 100644 index 00000000000..c55090cced5 --- /dev/null +++ b/JSON/Context.sublime-menu @@ -0,0 +1,29 @@ +// Packages/JSON/Context.sublime-menu + + +// This file is being maintained at: +// https://github.com/sublimehq/Packages/blob/master/JSON/Context.sublime-menu + + +[ + // visible only with JSON syntax highlighting + { + "caption": "JSON: Minify", + "command": "json_minify" + }, + { + "caption": "JSON: Prettify", + "command": "json_prettify" + }, + + + // visible only with JSONC syntax highlighting + { + "caption": "JSONC: Minify", + "command": "jsonc_minify" + }, + { + "caption": "JSONC: Prettify", + "command": "jsonc_prettify" + } +] diff --git a/JSON/Default.sublime-commands b/JSON/Default.sublime-commands new file mode 100644 index 00000000000..c6a9be5e676 --- /dev/null +++ b/JSON/Default.sublime-commands @@ -0,0 +1,29 @@ +// Packages/JSON/Default.sublime-commands + + +// This file is being maintained at: +// https://github.com/sublimehq/Packages/blob/master/JSON/Default.sublime-commands + + +[ + // visible only with JSON syntax highlighting + { + "caption": "JSON: Minify JSON", + "command": "json_minify" + }, + { + "caption": "JSON: Prettify JSON", + "command": "json_prettify" + }, + + + // visible only with JSONC syntax highlighting + { + "caption": "JSONC: Minify JSONC", + "command": "jsonc_minify" + }, + { + "caption": "JSONC: Prettify JSONC", + "command": "jsonc_prettify" + } +] diff --git a/JSON/Default.sublime-keymap b/JSON/Default.sublime-keymap index e11d9bce5c6..56ef9e4a4e7 100644 --- a/JSON/Default.sublime-keymap +++ b/JSON/Default.sublime-keymap @@ -1,63 +1,70 @@ +// Packages/JSON/Default.sublime-keymap + + +// This file is being maintained at: +// https://github.com/sublimehq/Packages/blob/master/JSON/Default.sublime-keymap + + [ - // Auto-pair quotations: "key": '|', - { "keys": ["'"], "command": "insert_snippet", "args": {"contents": "'$0'"}, "context": - [ - { "key": "setting.auto_match_enabled" }, - { "key": "selector", "operand": "source.json" }, - { "key": "selection_empty", "match_all": true }, - { "key": "preceding_text", "operator": "not_regex_contains", "operand": "['\\w]$", "match_all": true }, - { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |]|,|:|\\}|$)", "match_all": true } - ] - }, - - // Auto-pair quotations: "key": "|", - { "keys": ["\""], "command": "insert_snippet", "args": {"contents": "\"$0\""}, "context": - [ - { "key": "setting.auto_match_enabled" }, - { "key": "selector", "operand": "source.json" }, - { "key": "selection_empty", "match_all": true }, - { "key": "preceding_text", "operator": "not_regex_contains", "operand": "[\"\\w]$", "match_all": true }, - { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |]|,|:|\\}|$)", "match_all": true } - ] - }, - - // Auto-pair braces: "key": {|}, - { "keys": ["{"], "command": "insert_snippet", "args": {"contents": "{$0}"}, "context": - [ - { "key": "setting.auto_match_enabled" }, - { "key": "selector", "operand": "source.json" }, - { "key": "selection_empty", "match_all": true }, - { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |]|,|:|\\}|$)", "match_all": true } - ] - }, - - // Auto-pair square brackets: "key": [|], - { "keys": ["["], "command": "insert_snippet", "args": {"contents": "[$0]"}, "context": - [ - { "key": "setting.auto_match_enabled" }, - { "key": "selector", "operand": "source.json" }, - { "key": "selection_empty", "match_all": true }, - { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |]|,|:|\\}|$)", "match_all": true } - ] - }, - - // Add indented line in square brackets - { "keys": ["enter"], "command": "insert_snippet", "args": {"contents": "\n\t$0\n"}, "context": - [ - { "key": "setting.auto_indent" }, - { "key": "selector", "operand": "source.json" }, - { "key": "selection_empty", "match_all": true }, - { "key": "preceding_text", "operator": "regex_contains", "operand": "\\[$", "match_all": true }, - { "key": "following_text", "operator": "regex_contains", "operand": "^\\]", "match_all": true } - ] - }, - { "keys": ["shift+enter"], "command": "insert_snippet", "args": {"contents": "\n\t$0\n"}, "context": - [ - { "key": "setting.auto_indent" }, - { "key": "selector", "operand": "source.json" }, - { "key": "selection_empty", "match_all": true }, - { "key": "preceding_text", "operator": "regex_contains", "operand": "\\[$", "match_all": true }, - { "key": "following_text", "operator": "regex_contains", "operand": "^\\]", "match_all": true } - ] - }, -] \ No newline at end of file + // Auto-pair quotations: "key": '|', + { "keys": ["'"], "command": "insert_snippet", "args": {"contents": "'$0'"}, "context": + [ + { "key": "setting.auto_match_enabled" }, + { "key": "selector", "operand": "source.json" }, + { "key": "selection_empty", "match_all": true }, + { "key": "preceding_text", "operator": "not_regex_contains", "operand": "['\\w]$", "match_all": true }, + { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |]|,|:|\\}|$)", "match_all": true } + ] + }, + + // Auto-pair quotations: "key": "|", + { "keys": ["\""], "command": "insert_snippet", "args": {"contents": "\"$0\""}, "context": + [ + { "key": "setting.auto_match_enabled" }, + { "key": "selector", "operand": "source.json" }, + { "key": "selection_empty", "match_all": true }, + { "key": "preceding_text", "operator": "not_regex_contains", "operand": "[\"\\w]$", "match_all": true }, + { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |]|,|:|\\}|$)", "match_all": true } + ] + }, + + // Auto-pair braces: "key": {|}, + { "keys": ["{"], "command": "insert_snippet", "args": {"contents": "{$0}"}, "context": + [ + { "key": "setting.auto_match_enabled" }, + { "key": "selector", "operand": "source.json" }, + { "key": "selection_empty", "match_all": true }, + { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |]|,|:|\\}|$)", "match_all": true } + ] + }, + + // Auto-pair square brackets: "key": [|], + { "keys": ["["], "command": "insert_snippet", "args": {"contents": "[$0]"}, "context": + [ + { "key": "setting.auto_match_enabled" }, + { "key": "selector", "operand": "source.json" }, + { "key": "selection_empty", "match_all": true }, + { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |]|,|:|\\}|$)", "match_all": true } + ] + }, + + // Add indented line in square brackets + { "keys": ["enter"], "command": "insert_snippet", "args": {"contents": "\n\t$0\n"}, "context": + [ + { "key": "setting.auto_indent" }, + { "key": "selector", "operand": "source.json" }, + { "key": "selection_empty", "match_all": true }, + { "key": "preceding_text", "operator": "regex_contains", "operand": "\\[$", "match_all": true }, + { "key": "following_text", "operator": "regex_contains", "operand": "^\\]", "match_all": true } + ] + }, + { "keys": ["shift+enter"], "command": "insert_snippet", "args": {"contents": "\n\t$0\n"}, "context": + [ + { "key": "setting.auto_indent" }, + { "key": "selector", "operand": "source.json" }, + { "key": "selection_empty", "match_all": true }, + { "key": "preceding_text", "operator": "regex_contains", "operand": "\\[$", "match_all": true }, + { "key": "following_text", "operator": "regex_contains", "operand": "^\\]", "match_all": true } + ] + }, +] diff --git a/JSON/Fold.tmPreferences b/JSON/Fold.tmPreferences deleted file mode 100644 index 09d2cbf5356..00000000000 --- a/JSON/Fold.tmPreferences +++ /dev/null @@ -1,27 +0,0 @@ - - - - scope - source.json - settings - - indentationFoldingEnabled - - foldScopes - - - begin - punctuation.section.sequence.begin - end - punctuation.section.sequence.end - - - begin - punctuation.section.mapping.begin - end - punctuation.section.mapping.end - - - - - diff --git a/JSON/Folding Rules - JSON.tmPreferences b/JSON/Folding Rules - JSON.tmPreferences new file mode 100644 index 00000000000..6fbb72cbbe6 --- /dev/null +++ b/JSON/Folding Rules - JSON.tmPreferences @@ -0,0 +1,27 @@ + + + + scope + source.json - (source.json.json-dotnet | source.json.json5 | source.json.jsonc) + settings + + indentationFoldingEnabled + + foldScopes + + + begin + punctuation.definition.mapping.begin + end + punctuation.definition.mapping.end + + + begin + punctuation.definition.sequence.begin + end + punctuation.definition.sequence.end + + + + + diff --git a/JSON/Folding Rules - JSON5.tmPreferences b/JSON/Folding Rules - JSON5.tmPreferences new file mode 100644 index 00000000000..a77da66569c --- /dev/null +++ b/JSON/Folding Rules - JSON5.tmPreferences @@ -0,0 +1,31 @@ + + + + scope + source.json.json5 + settings + + foldScopes + + + begin + punctuation.definition.comment.begin + end + punctuation.definition.comment.end + + + begin + punctuation.definition.mapping.begin + end + punctuation.definition.mapping.end + + + begin + punctuation.definition.sequence.begin + end + punctuation.definition.sequence.end + + + + + diff --git a/JSON/Folding Rules - JSONC.tmPreferences b/JSON/Folding Rules - JSONC.tmPreferences new file mode 100644 index 00000000000..5c219270eeb --- /dev/null +++ b/JSON/Folding Rules - JSONC.tmPreferences @@ -0,0 +1,31 @@ + + + + scope + source.json.jsonc + settings + + foldScopes + + + begin + punctuation.definition.comment.begin + end + punctuation.definition.comment.end + + + begin + punctuation.definition.mapping.begin + end + punctuation.definition.mapping.end + + + begin + punctuation.definition.sequence.begin + end + punctuation.definition.sequence.end + + + + + diff --git a/JSON/Folding Rules - JSON_dotNET.tmPreferences b/JSON/Folding Rules - JSON_dotNET.tmPreferences new file mode 100644 index 00000000000..6b1b4bd8892 --- /dev/null +++ b/JSON/Folding Rules - JSON_dotNET.tmPreferences @@ -0,0 +1,27 @@ + + + + scope + source.json.json-dotnet + settings + + indentationFoldingEnabled + + foldScopes + + + begin + punctuation.definition.mapping.begin + end + punctuation.definition.mapping.end + + + begin + punctuation.definition.sequence.begin + end + punctuation.definition.sequence.end + + + + + diff --git a/JSON/JSON.sublime-completions b/JSON/JSON.sublime-completions new file mode 100644 index 00000000000..2bffbac3e4a --- /dev/null +++ b/JSON/JSON.sublime-completions @@ -0,0 +1,27 @@ +{ + "scope": "source.json", + "completions": + [ + { + "trigger": "true", + "contents": "true", + "annotation": "constant.language", + "kind": ["snippet", "s", "Snippet"], + "details": "literal JSON constant" + }, + { + "trigger": "false", + "contents": "false", + "annotation": "constant.language", + "kind": ["snippet", "s", "Snippet"], + "details": "literal JSON constant" + }, + { + "trigger": "null", + "contents": "null", + "annotation": "constant.language", + "kind": ["snippet", "s", "Snippet"], + "details": "literal JSON constant" + } + ] +} diff --git a/JSON/JSON.sublime-settings b/JSON/JSON.sublime-settings new file mode 100644 index 00000000000..40b58cd7ac7 --- /dev/null +++ b/JSON/JSON.sublime-settings @@ -0,0 +1,13 @@ +// Packages/JSON/JSON.sublime-settings +// Settings - Syntax Specific (Default) +// +// This file is being maintained at: +// https://github.com/sublimehq/Packages/blob/master/JSON/JSON.sublime-settings + + +{ + "default_extension": "json", + + // whether `on_pre_save_async` events auto-trigger the `json_prettify` command + "json.auto_prettify": false +} diff --git a/JSON/JSON.sublime-syntax b/JSON/JSON.sublime-syntax index 9d1aa3aa281..239981a8d96 100644 --- a/JSON/JSON.sublime-syntax +++ b/JSON/JSON.sublime-syntax @@ -1,171 +1,534 @@ %YAML 1.2 --- +# YAML Documentation: +# https://yaml.org/spec/1.2/spec.html +# Sublime Text Documentation: +# https://www.sublimetext.com/docs/syntax.html#ver-dev +# https://www.sublimetext.com/docs/syntax.html#testing:ver-dev +# https://www.sublimetext.com/docs/scope_naming.html +# This file is being maintained at: +# https://github.com/sublimehq/Packages/blob/master/JSON/JSON.sublime-syntax + name: JSON scope: source.json version: 2 file_extensions: - json - - sublime-build - - sublime-color-scheme - - sublime-commands - - sublime-completions - - sublime-keymap - - sublime-macro - - sublime-menu - - sublime-mousemap - - sublime-project - - sublime-settings - - sublime-theme - - sublime-workspace - - ipynb + # https://www.json.org/json-en.html + # https://datatracker.ietf.org/doc/html/rfc7159 + # https://www.ecma-international.org/publications-and-standards/standards/ecma-404/ + +hidden_file_extensions: + - .bowerrc + # Bower + # https://bower.io/docs/config/ + + - .htmlhintrc + # HTML hint + # https://htmlhint.com/docs/user-guide/getting-started + + - .jscsrc + # JavaScript Code Style Configuration + # https://jscs-dev.github.io + + - .markdownlintrc + # https://github.com/DavidAnson/markdownlint + + - .tern-config + # Tern.js Server Configuration + # https://ternjs.net/doc/manual.html#server + + - .tern-project + # Tern.js Project Configuration + # https://ternjs.net/doc/manual.html#configuration + + - .watchmanconfig + # Facebook Watchman + # root specific configuration file + # https://facebook.github.io/watchman/docs/config.html + - Pipfile.lock + # Pipfile + # https://github.com/pypa/pipfile + + - avsc + # Pure JavaScript implementation of the Avro specification + # https://github.com/mtth/avsc + + - composer.lock + # Composer lock file + # https://getcomposer.org/doc/01-basic-usage.md + + - css.map + # CSS Source Map + + - geojson + # JSON for geographic data structures + # https://geojson.org + # https://datatracker.ietf.org/wg/geojson/charter/ + # https://datatracker.ietf.org/doc/html/rfc7946 + - gltf + # glTF Runtime 3D asset delivery + # https://www.khronos.com/gltf + + - har + # HTTP Archive Format + + - ipynb + # Jupyter Notebook, formerly known as iPython Notebook + # https://jupyter.org/documentation + + - js.map + # JavaScript Source Map + + - jsonld + # JSON for Linking Data + # https://json-ld.org + + - ldjson + # JSON for Linking Data + # https://json-ld.org + + - schema + # JSON Schema + # https://json-schema.org/learn + + - tfstate + # Hashicorp Terraform State + # https://www.terraform.io/docs/language/state/index.html + + - tfstate.backup + # Hashicorp Terraform State + # https://www.terraform.io/docs/language/state/index.html + + - topojson + # TopoJSON, an extension to GeoJSON + # https://github.com/topojson/topojson-specification + + - ts.map + # TypeScript Source Map + + - webapp + # Web app manifests + # https://developer.mozilla.org/en-US/docs/Web/Manifest + + - webmanifest + # Web app manifests + # https://developer.mozilla.org/en-US/docs/Web/Manifest first_line_match: |- (?xi: - ^ \s* // .*? -\*- .*? \bjson\b .*? -\*- # editorconfig + ^ \s* // .*? -\*- .*? \bjson\b .*? -\*- # editorconfig ) +variables: + exponent: (?:[eE][-+]?\d+) + pos_integer_decimal: (?:0|[1-9]\d*) + html_entity: '&([a-zA-Z0-9]+|#\d+|#[Xx]\h+);' + email_domain: '[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?' + email_user: '[a-zA-Z0-9.!#$%&''*+/=?^_`{|}~-]+' + +######################################################################################################################## + contexts: prototype: - include: comments main: - - include: value + - match: (?=\S) + push: + - invalid-remainder + - any-else-pop - value: - - include: constant - - include: number - - include: string - - include: array - - include: object +####[ Helpers ]######################################################################################################### - array: - - match: \[ - scope: punctuation.section.sequence.begin.json - push: - - meta_scope: meta.sequence.json - - match: \] - scope: punctuation.section.sequence.end.json - pop: 1 - - include: value - - match: ',' - scope: punctuation.separator.sequence.json - - match: '[^\s\]]' - scope: invalid.illegal.expected-sequence-separator.json + any: + - include: structures + - include: values + + any-else-pop: + - include: any + - include: else-pop + + structures: + - include: objects + - include: arrays + + values: + - include: constants + - include: numbers + - include: strings + + invalid-remainder: + - match: '[,:]' + scope: invalid.illegal.unexpected-separator.json + - match: '[^,:\s]+' + scope: invalid.illegal.unexpected-code-after-first-structure-or-value.json + +####[ Prototypes ]###################################################################################################### + + else-pop: + - match: (?=\S) + pop: 1 + + eol-pop: + - match: '$\n?' + pop: 1 + +####[ Comments ]######################################################################################################## comments: - - match: /\*\*(?!/) - scope: punctuation.definition.comment.json - push: - - meta_scope: comment.block.documentation.json - - meta_include_prototype: false - - match: \*/ - pop: 1 - - match: ^\s*(\*)(?!/) - captures: - 1: punctuation.definition.comment.json + - include: comment-line + - include: comment-block + + comment-line: + - match: // + push: comment-line-content + + comment-line-content: + - meta_include_prototype: false + - meta_scope: invalid.illegal.comment.json + - include: eol-pop + + comment-block: + - match: /\*\*+/ + scope: invalid.illegal.comment.json - match: /\* - scope: punctuation.definition.comment.json - push: - - meta_scope: comment.block.json - - meta_include_prototype: false - - match: \*/ - pop: 1 - - match: (//).*$\n? - scope: comment.line.double-slash.js - captures: - 1: punctuation.definition.comment.json + push: comment-block-content + + comment-block-content: + - meta_include_prototype: false + - meta_scope: invalid.illegal.comment.json + - match: \*/ + pop: 1 + +####[ Constants ]####################################################################################################### + + constants: + - include: valid-constants + - include: invalid-constants - constant: + valid-constants: + - match: \b(?:null)\b + scope: constant.language.null.json + pop: 1 - match: \b(?:false|true)\b scope: constant.language.boolean.json - - match: \bnull\b - scope: constant.language.null.json + pop: 1 - number: - # handles integer and decimal numbers - - match: (-?)((?:0|[1-9]\d*)(?:(?:(\.)\d+)(?:[eE][-+]?\d+)?|(?:[eE][-+]?\d+))) + invalid-constants: + # when erroneously containing upper case letters + - match: \b(?i:null)\b + scope: invalid.illegal.expected-lower-case-null.json + pop: 1 + - match: \b(?i:false|true)\b + scope: invalid.illegal.expected-lower-case-boolean.json + pop: 1 + +####[ Numbers ]######################################################################################################### + + numbers: + - include: float + - include: integer + + float: + - include: decimal-float + + decimal-float: + - match: |- + (?x: + (?:(-)|(\+))? + ( + {{pos_integer_decimal}} + (?: + (\.)\d+ {{exponent}}? # 1.1 1.1e1 1.1e-1 1.1e+1 + | {{exponent}} # 1e1 1+e1 1-e1 + ) + ) + ) scope: meta.number.float.decimal.json captures: - 1: keyword.operator.arithmetic.json - 2: constant.numeric.value.json - 3: punctuation.separator.decimal.json - - match: (-?)(0|[1-9]\d*) + 1: constant.numeric.sign.json + 2: invalid.illegal.numeric-sign.json + 3: constant.numeric.value.json + 4: punctuation.separator.decimal.json + pop: 1 + + integer: + - include: decimal-integer + + decimal-integer: + - match: (?:(-)|(\+))?({{pos_integer_decimal}}) scope: meta.number.integer.decimal.json captures: - 1: keyword.operator.arithmetic.json - 2: constant.numeric.value.json + 1: constant.numeric.sign.json + 2: invalid.illegal.numeric-sign.json + 3: constant.numeric.value.json + pop: 1 - object: - # a JSON object - - match: \{ - scope: punctuation.section.mapping.begin.json - push: - - meta_scope: meta.mapping.json - - match: \} - scope: punctuation.section.mapping.end.json - pop: 1 - - match: \" - scope: punctuation.definition.string.begin.json - push: - - clear_scopes: 1 - - meta_scope: meta.mapping.key.json string.quoted.double.json - - meta_include_prototype: false - - include: inside-string - - match: ':' - scope: punctuation.separator.key-value.json - push: - - match: ',|\s?(?=\})' - scope: invalid.illegal.expected-mapping-value.json - pop: 1 - - match: (?=\S) - set: - - clear_scopes: 1 - - meta_scope: meta.mapping.value.json - - include: value - - match: '' - set: - - match: ',' - scope: punctuation.separator.sequence.json - pop: 1 - - match: \s*(?=\}) - pop: 1 - - match: \s(?!/[/*])(?=[^\s,])|[^\s,] - scope: invalid.illegal.expected-mapping-separator.json - pop: 1 - - match: '[^\s\}]' - scope: invalid.illegal.expected-mapping-key.json - - string: +####[ Strings ]######################################################################################################### + + strings: + - include: double-quoted-string + + double-quoted-string: - match: \" scope: punctuation.definition.string.begin.json - push: inside-string + set: double-quoted-string-content - inside-string: - - meta_scope: string.quoted.double.json + double-quoted-string-content: - meta_include_prototype: false + - meta_scope: >- + meta.string.json + string.quoted.double.json - match: \" scope: punctuation.definition.string.end.json pop: 1 - - include: string-escape + - include: double-quoted-string-escape-characters + - include: links - match: \n scope: invalid.illegal.unclosed-string.json pop: 1 - string-escape: + links: + - include: autolink-email + - include: autolink-inet + + autolink-email: - match: |- - (?x: # turn on extended mode - \\ # a literal backslash - (?: # ...followed by... - ["\\/bfnrt] # one of these characters - | # ...or... - u # a u - [0-9a-fA-F]{4} # and four hex digits + (?x: + (<) + ( + (?:mailto(:))? + {{email_user}} + (@) + {{email_domain}}(?:\.{{email_domain}})* ) + (>) ) - scope: constant.character.escape.json + scope: meta.link.email.json + captures: + 1: punctuation.definition.link.begin.json + 2: markup.underline.link.json + 3: punctuation.separator.path.json + 4: punctuation.separator.path.json + 5: punctuation.definition.link.end.json + - match: |- + (?x: + [\w.+-]+ + (@) + [\w-]+(?:\.(?:(?![._-][\W])[\w_-])+)+(?![_-]) + ) + scope: >- + meta.link.email.json + markup.underline.link.json + captures: + 1: punctuation.separator.path.json + + autolink-inet: + - match: <(?=[[:alpha:]][[:alnum:].+-]+:) + scope: punctuation.definition.link.begin.json + push: + - autolink-inet-angled-content + - link-url-scheme-separator + - match: (?:(?:https|http|ftp)(://)|www\.)[\w-]+ + captures: + 1: punctuation.separator.path.json + push: autolink-inet-unquoted-content + + autolink-inet-angled-content: + - meta_scope: meta.link.inet.json + - meta_content_scope: markup.underline.link.json + - match: \> + scope: punctuation.definition.link.end.json + pop: 1 + - match: (?=\s) + pop: 1 + - include: autolink-inet-common + + autolink-inet-unquoted-content: + - meta_scope: >- + meta.link.inet.json + markup.underline.link.json + - match: (?=(?:\)|(?:{{html_entity}})*)[?!.,:*_~]*[\s<]) + pop: 1 + - include: autolink-inet-common + + autolink-inet-group: + - match: \) + pop: 1 + - match: (?=(?:{{html_entity}})*[?!.,:*_~]*[\s<]) + pop: 1 + - include: autolink-inet-common + + autolink-inet-common: + - match: \( + push: autolink-inet-group + - match: '[/&?#]' + scope: punctuation.separator.path.json + - match: (%)\h{2} + scope: constant.character.escape.url.json + captures: + 1: punctuation.definition.escape.json + + link-url-scheme-separator: + - match: ':/{,2}' + scope: punctuation.separator.path.json + pop: 1 + + double-quoted-string-escape-characters: + - match: (\\)\" + scope: constant.character.escape.double-quote.json # quotation mark + captures: + 1: punctuation.definition.escape.json + - include: string-escape-characters + + string-escape-characters: + - include: valid-string-escape-characters + - include: invalid-string-escape-characters + + valid-string-escape-characters: + - match: (\\)\\ + scope: constant.character.escape.back-slash.json # reverse solidus + captures: + 1: punctuation.definition.escape.json + - match: (\\)\/ + scope: constant.character.escape.forward-slash.json # solidus + captures: + 1: punctuation.definition.escape.json + - match: (\\)b + scope: constant.character.escape.backspace.json + captures: + 1: punctuation.definition.escape.json + - match: (\\)f + scope: constant.character.escape.form-feed.json + captures: + 1: punctuation.definition.escape.json + - match: (\\)n + scope: constant.character.escape.newline.json # linefeed + captures: + 1: punctuation.definition.escape.json + - match: (\\)r + scope: constant.character.escape.carriage-return.json + captures: + 1: punctuation.definition.escape.json + - match: (\\)t + scope: constant.character.escape.horizontal-tab.json + captures: + 1: punctuation.definition.escape.json + - match: (\\)u[0-9a-fA-F]{4} + scope: >- + constant.character.escape.unicode-symbol.basic-multilingual-plane.json + captures: + 1: punctuation.definition.escape.json + + invalid-string-escape-characters: - match: \\. scope: invalid.illegal.unrecognized-string-escape.json + +####[ Sequences ]####################################################################################################### + + arrays: + - match: \[ + scope: punctuation.definition.sequence.begin.json + set: + - array-body + - array-item + + array-body: + - meta_scope: meta.sequence.list.json + - match: \] + scope: punctuation.definition.sequence.end.json + pop: 1 + - include: array-separators + + array-separators: + - match: (?=,) + branch_point: array-separators + branch: + - valid-array-separator + - invalid-array-separator + - match: (?=\S) + push: array-item + + valid-array-separator: + - match: ',' + scope: punctuation.separator.sequence.json + set: array-expect-value + + array-expect-value: + - match: (?=\]) + fail: array-separators + - include: array-item + + array-item: + - include: any + - include: invalid-array-separator + + invalid-array-separator: + - match: ',' + scope: invalid.illegal.unexpected-separator.json + - include: else-pop + +####[ Mappings ]######################################################################################################## + + # FIXME: leading separators + # FIXME: trailing commas + + objects: + - match: \{ + scope: punctuation.definition.mapping.begin.json + set: object-body + + object-body: + - meta_scope: meta.mapping.json + - match: \} + scope: punctuation.definition.mapping.end.json + pop: 1 + - include: mapping-key + - include: mapping-separator + - match: '[^\s\}]' + scope: invalid.illegal.expected-mapping-key.json + + mapping-key: + - match: \" + scope: punctuation.definition.string.begin.json + push: mapping-key-double-quoted + + mapping-key-double-quoted: + - clear_scopes: 1 + - meta_include_prototype: false + - meta_scope: >- + meta.mapping.key.json + meta.string.json + string.quoted.double.json + - include: double-quoted-string-content + + mapping-separator: + - match: ':' + scope: punctuation.separator.key-value.json + push: mapping-expect-value + + mapping-expect-value: + - match: ',|\s?(?=\})' + scope: invalid.illegal.expected-mapping-value.json + pop: 1 + - match: (?=\S) + set: + - mapping-value + - any-else-pop + + mapping-value: + - clear_scopes: 1 + - meta_scope: meta.mapping.value.json + - match: ',' + scope: punctuation.separator.sequence.json + pop: 1 + - match: \s*(?=\}) + pop: 1 + - match: \s(?!/[/*])(?=[^\s,])|[^\s,] + scope: invalid.illegal.expected-mapping-separator.json + pop: 1 diff --git a/JSON/JSON5.sublime-completions b/JSON/JSON5.sublime-completions new file mode 100644 index 00000000000..6cfbd1d9c3d --- /dev/null +++ b/JSON/JSON5.sublime-completions @@ -0,0 +1,48 @@ +{ + "scope": "source.json.json5", + "completions": + [ + { + "trigger": "Infinity", + "contents": "Infinity", + "annotation": "constant.language", + "kind": ["snippet", "s", "Snippet"], + "details": "JSON5 number

IEEE 754 positive infinity
literal constant \"Infinity\"" + }, + { + "trigger": "Infinity", + "contents": "+Infinity", + "annotation": "constant.language", + "kind": ["snippet", "s", "Snippet"], + "details": "JSON5 number

IEEE 754 positive infinity
literal constant \"Infinity\" with an optional plus as prefix" + }, + { + "trigger": "Infinity", + "contents": "-Infinity", + "annotation": "constant.language", + "kind": ["snippet", "s", "Snippet"], + "details": "JSON5 number

IEEE 754 negative infinity
literal constant \"-Infinity\"" + }, + { + "trigger": "NaN", + "contents": "NaN", + "annotation": "constant.language", + "kind": ["snippet", "s", "Snippet"], + "details": "JSON5 number

IEEE 754 NaN
literal constant \"NaN\"" + }, + { + "trigger": "NaN", + "contents": "+NaN", + "annotation": "constant.language", + "kind": ["snippet", "s", "Snippet"], + "details": "JSON5 number

IEEE 754 NaN
literal constant \"NaN\" with an optional plus as prefix" + }, + { + "trigger": "NaN", + "contents": "-NaN", + "annotation": "constant.language", + "kind": ["snippet", "s", "Snippet"], + "details": "JSON5 number

IEEE 754 NaN
literal constant \"NaN\" with an optional minus as prefix" + } + ] +} diff --git a/JSON/JSON5.sublime-settings b/JSON/JSON5.sublime-settings new file mode 100644 index 00000000000..047cb2547ad --- /dev/null +++ b/JSON/JSON5.sublime-settings @@ -0,0 +1,10 @@ +// Packages/JSON/JSON5.sublime-settings +// Settings - Syntax Specific (Default) +// +// This file is being maintained at: +// https://github.com/sublimehq/Packages/blob/master/JSON/JSON5.sublime-settings + + +{ + "default_extension": "json5" +} diff --git a/JSON/JSON5.sublime-syntax b/JSON/JSON5.sublime-syntax new file mode 100644 index 00000000000..ffe7c7a8c1f --- /dev/null +++ b/JSON/JSON5.sublime-syntax @@ -0,0 +1,255 @@ +%YAML 1.2 +--- +# YAML Documentation: +# https://yaml.org/spec/1.2/spec.html +# Sublime Text Documentation: +# https://www.sublimetext.com/docs/syntax.html#ver-dev +# https://www.sublimetext.com/docs/syntax.html#testing:ver-dev +# https://www.sublimetext.com/docs/scope_naming.html +# This file is being maintained at: +# https://github.com/sublimehq/Packages/blob/master/JSON/JSON5.sublime-syntax + +name: JSON5 +scope: source.json.json5 +version: 2 + +# https://www.sublimetext.com/docs/syntax.html#inheritance +extends: Packages/JSON/JSONC.sublime-syntax + +file_extensions: + - json5 + # https://json5.org/ + # https://spec.json5.org/#summary-of-features + # https://262.ecma-international.org/5.1/ + +hidden_file_extensions: + - .babelrc + # Babel.js File-relative Configuration + # https://babeljs.io/docs/en/config-files + + - .babelrc.json + # Babel.js File-relative Configuration + # https://babeljs.io/docs/en/config-files + + - .jupyterlab-settings + # JupyterLab User Settings + # https://jupyterlab.readthedocs.io/en/stable/user/directories.html?highlight=json5#jupyterlab-user-settings-directory + + - .parcelrc + # parcel Bundler Configuration + # https://github.com/parcel-bundler/parcel + # https://parceljs.org/features/plugins/#.parcelrc + + - .postcssrc.json + # PostCSS Configuration + # https://postcss.org + + - babel.config.json + # Babel.js Project-wide Configuration + # https://babeljs.io/docs/en/config-files + + - next.config.json + # Vercel Next.js Configuration + # https://nextjs.org/docs/api-reference/next.config.js/introduction + + - nextrc.json + # Vercel Next.js Configuration + # https://nextjs.org/docs/api-reference/next.config.js/introduction + + - techdocs_metadata.json + # Spotify's @backstage/techdocs_common Configuration + # https://github.com/backstage/backstage/tree/master/packages/techdocs-common + # https://backstage.io/docs/features/techdocs/techdocs-overview + +first_line_match: |- + (?xi: + ^ \s* // .*? -\*- .*? \bjson5\b .*? -\*- # editorconfig + ) + +variables: + + # Boost documentation: + # https://www.boost.org/doc/libs/1_64_0/libs/regex/doc/html/boost_regex/syntax/perl_syntax.html + # Unicode documentation: + # https://www.unicode.org/versions/latest/ + # https://www.unicode.org/Public/UCD/latest/ucd/ + # Oniguruma documentation: + # https://github.com/kkos/oniguruma/blob/master/doc/RE + # https://github.com/kkos/oniguruma/blob/master/doc/UNICODE_PROPERTIES + + identifier_escape: (?:\\u(?:\h{4}|\{\h+\})) + identifier_start: (?:[_$\p{L}\p{Nl}]|{{identifier_escape}}) + identifier_part: (?:[_$\p{L}\p{Nl}\p{Mn}\p{Mc}\p{Nd}\p{Pc}\x{200C}\x{200D}]|{{identifier_escape}}) + identifier_break: (?!{{identifier_part}}) + + identifier_name: (?:{{identifier_start}}{{identifier_part}}*{{identifier_break}}) + +######################################################################################################################## + +contexts: + + # TODO: check whitespace valid chars + +####[ Numbers ]######################################################################################################### + + decimal-float: + - match: |- + (?x: + ([-+]?) + ( + {{pos_integer_decimal}} + (?: + (\.)\d* {{exponent}}? # 1. 1.e1 1.e-1 1.e+1 1.1 1.1e1 1.1e-1 1.1e+1 + | {{exponent}} # 1e1 1+e1 1-e1 + ) + | (\.)\d+ {{exponent}}? # .1 .1e1 .1e+1 .1e-1 + ) + ) + scope: meta.number.float.decimal.json5 + captures: + 1: constant.numeric.sign.json5 + 2: constant.numeric.value.json5 + 3: punctuation.separator.decimal.json5 + 4: punctuation.separator.decimal.json5 + pop: 1 + - match: ([-+]?)(Infinity) + scope: meta.number.float.decimal.json5 + captures: + 1: constant.numeric.sign.json5 + 2: constant.language.infinity.json5 + pop: 1 + - match: ([-+]?)(NaN) + scope: meta.number.float.decimal.json5 + captures: + 1: constant.numeric.sign.json5 + 2: constant.language.nan.json5 + pop: 1 + + # when erroneously containing wrongly cased letters + - match: ([-+]?)(?i:(infinity)) + scope: meta.number.float.decimal.json5 + captures: + 1: constant.numeric.sign.json5 + 2: invalid.illegal.expected-language-constant.json5 + pop: 1 + - match: ([-+]?)(?i:(nan)) + scope: meta.number.float.decimal.json5 + captures: + 1: constant.numeric.sign.json5 + 2: invalid.illegal.expected-language-constant.json5 + pop: 1 + + integer: + - meta_prepend: true + - include: hexadecimal-integer + + decimal-integer: + - match: ([-+]?)({{pos_integer_decimal}}) + scope: meta.number.integer.decimal.json5 + captures: + 1: constant.numeric.sign.json5 + 2: constant.numeric.value.json5 + pop: 1 + + hexadecimal-integer: + - match: ([-+]?)(0[xX])(\h+) + scope: meta.number.integer.hexadecimal.json5 + captures: + 1: constant.numeric.sign.json5 + 2: constant.numeric.base.json5 + 3: constant.numeric.value.json5 + pop: 1 + +####[ Strings ]######################################################################################################### + + strings: + - meta_append: true + - include: single-quoted-string + + single-quoted-string: + - match: \' + scope: punctuation.definition.string.begin.json5 + set: single-quoted-string-content + + single-quoted-string-content: + - meta_include_prototype: false + - meta_scope: >- + meta.string.json5 + string.quoted.single.json5 + - match: \' + scope: punctuation.definition.string.end.json5 + pop: 1 + - include: single-quoted-string-escape-characters + - match: \n + scope: invalid.illegal.unclosed-string.json5 + pop: 1 + + single-quoted-string-escape-characters: + - match: \\\' + scope: constant.character.escape.single-quote.json5 + - include: string-escape-characters + + valid-string-escape-characters: + - meta_prepend: true + - match: ((\\)\x{2028})(.*)$\n? + captures: + 1: constant.character.escape.line-separator.json5 + 2: punctuation.separator.continuation.line.json5 + 3: invalid.illegal.expected-eol-after-line-continuation.json5 + - match: ((\\)\x{2029})(.*)$\n? + captures: + 1: constant.character.escape.paragraph-separator.json5 + 2: punctuation.separator.continuation.line.json5 + 3: invalid.illegal.expected-eol-after-line-continuation.json5 + - match: (\\)$\n? + captures: + 1: punctuation.separator.continuation.line.json5 + - match: \\v + scope: constant.character.escape.vertical-tab.json5 + - match: (\\0)([0-9])? + captures: + 1: constant.character.escape.null.json5 + 2: invalid.illegal.unexpected-digit-character.json5 + - match: \\x[0-9a-fA-F]{2} + scope: constant.character.escape.unicode-symbol.basic-latin-or-latin-1-supplement.json5 + - match: \\u[0-9a-fA-F]{4}\\u[0-9a-fA-F]{4} + scope: constant.character.escape.unicode-symbol.utf16-surrogate-pair.json5 + + invalid-string-escape-characters: + - meta_prepend: true + - match: ([^\\])(?:\x{2028}|\x{2029}) + captures: + 1: invalid.illegal.expected-backslash-char.json5 + +####[ Mappings ]######################################################################################################## + + mapping-key: + - meta_append: true + - match: \' + scope: punctuation.definition.string.begin.json5 + push: mapping-key-single-quoted + + # looking ahead at `identifier_start` would've been faster with possibly + # invalid matches, but we want to make sure we only match valid ecma + # `identifier_name`s as keys + - match: (?={{identifier_name}}) + push: mapping-key-ecma + + mapping-key-ecma: + - clear_scopes: 1 + - meta_include_prototype: false + - meta_scope: >- + meta.mapping.key.json5 + meta.string.json5 + string.unquoted.plain.json5 + - match: '{{identifier_break}}' + pop: 1 + + mapping-key-single-quoted: + - clear_scopes: 1 + - meta_include_prototype: false + - meta_scope: >- + meta.mapping.key.json5 + meta.string.json5 + string.quoted.single.json5 + - include: single-quoted-string-content diff --git a/JSON/JSONC.sublime-settings b/JSON/JSONC.sublime-settings new file mode 100644 index 00000000000..9bd53bcb1f2 --- /dev/null +++ b/JSON/JSONC.sublime-settings @@ -0,0 +1,10 @@ +// Packages/JSON/JSONC.sublime-settings +// Settings - Syntax Specific (Default) +// +// This file is being maintained at: +// https://github.com/sublimehq/Packages/blob/master/JSON/JSONC.sublime-settings + + +{ + "default_extension": "jsonc" +} diff --git a/JSON/JSONC.sublime-syntax b/JSON/JSONC.sublime-syntax new file mode 100644 index 00000000000..280dccc816a --- /dev/null +++ b/JSON/JSONC.sublime-syntax @@ -0,0 +1,136 @@ +%YAML 1.2 +--- +# YAML Documentation: +# https://yaml.org/spec/1.2/spec.html +# Sublime Text Documentation: +# https://www.sublimetext.com/docs/syntax.html#ver-dev +# https://www.sublimetext.com/docs/syntax.html#testing:ver-dev +# https://www.sublimetext.com/docs/scope_naming.html +# This file is being maintained at: +# https://github.com/sublimehq/Packages/blob/master/JSON/JSONC.sublime-syntax + +name: JSONC +scope: source.json.jsonc +version: 2 + +# https://www.sublimetext.com/docs/syntax.html#inheritance +extends: Packages/JSON/JSON.sublime-syntax + +file_extensions: + - jsonc + + - sublime-build # https://www.sublimetext.com/docs/build_systems.html + - sublime-color-scheme # https://www.sublimetext.com/docs/color_schemes.html + - sublime-commands + - sublime-completions # https://www.sublimetext.com/docs/completions.html + - sublime-keymap # https://www.sublimetext.com/docs/key_bindings.html + - sublime-macro + - sublime-menu # https://www.sublimetext.com/docs/menus.html + - sublime-mousemap + - sublime-project # https://www.sublimetext.com/docs/projects.html + - sublime-settings # https://www.sublimetext.com/docs/settings.html + - sublime-theme # https://www.sublimetext.com/docs/themes.html + - sublime-workspace # https://www.sublimetext.com/docs/projects.html + +hidden_file_extensions: + - .ember-cli + + - .esformatter + # esformatter: ECMAScript code formatter + # https://github.com/millermedeiros/esformatter + + - .eslintrc + # ESLint Configuration + # https://eslint.org/docs/user-guide/configuring/ + + - .eslintrc.json + # ESLint Configuration + # https://eslint.org/docs/user-guide/configuring/ + + - .hintrc + # Webhint Configuration + # https://webhint.io/docs/user-guide/configuring-webhint/summary/ + + - .htmlhintrc + # HTMLHint Configuration + # https://htmlhint.com/docs/user-guide/configuration + + - .jsfmtrc + # jsfmt: For formatting, searching and re-writing JavaScript + # https://github.com/rdio/jsfmt#formatting + + - .jshintrc + # JSHint + # https://www.jshint.com/docs/#options + + - .jslintrc + # JSLint's implementation of JSHint + # https://www.jslint.com/lint.html + + - .stylintrc + # stylint Configuration + # https://github.com/SimenB/stylint + + - .swcrc + # swc Configuration + # https://swc.rs/docs/configuring-swc + + - eslintrc.json + # ESLint Configuration + # https://eslint.org/docs/user-guide/configuring/ + + - languagebabel + + - tsconfig.json + # TypeScript Configuration + # https://www.typescriptlang.org/docs/handbook/tsconfig-json.html + +first_line_match: |- + (?xi: + ^ \s* // .*? -\*- .*? \bjsonc\b .*? -\*- # editorconfig + ) + +######################################################################################################################## + +contexts: + +####[ Comments ]######################################################################################################## + + comment-line: + - match: // + scope: punctuation.definition.comment.jsonc + push: comment-line-content + + comment-line-content: + - meta_include_prototype: false + - meta_scope: comment.line.double-slash.jsonc + - include: eol-pop + + comment-block: + # empty block comments + - match: (/\*)\**(\*/) + scope: comment.block.empty.jsonc + captures: + 1: punctuation.definition.comment.begin.jsonc + 2: punctuation.definition.comment.end.jsonc + # normal block comments + - match: /\* + scope: punctuation.definition.comment.begin.jsonc + push: comment-block-content + + comment-block-content: + - meta_include_prototype: false + - meta_scope: comment.block.jsonc + - include: comment-block-end + + comment-block-end: + - match: \*/ + scope: punctuation.definition.comment.end.jsonc + pop: 1 + +####[ Sequences ]####################################################################################################### + + array-separators: + - match: ',' + scope: punctuation.separator.sequence.jsonc + push: array-item diff --git a/JSON/JSON_dotNET.sublime-syntax b/JSON/JSON_dotNET.sublime-syntax new file mode 100644 index 00000000000..cd20d59dbae --- /dev/null +++ b/JSON/JSON_dotNET.sublime-syntax @@ -0,0 +1,106 @@ +%YAML 1.2 +--- +# YAML Documentation: +# https://yaml.org/spec/1.2/spec.html +# Sublime Text Documentation: +# https://www.sublimetext.com/docs/syntax.html#ver-dev +# https://www.sublimetext.com/docs/syntax.html#testing:ver-dev +# https://www.sublimetext.com/docs/scope_naming.html +# This file is being maintained at: +# https://github.com/sublimehq/Packages/blob/master/JSON/JSON_dotNET.sublime-syntax +# +# Date formatting: +# https://www.iso.org/standard/70907.html (Basic rules) +# https://www.iso.org/standard/70908.html (Extensions) +# https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings + +name: 'JSON .NET' +scope: source.json.json-dotnet +version: 2 + +# https://www.sublimetext.com/docs/syntax.html#inheritance +extends: Packages/JSON/JSON.sublime-syntax + +first_line_match: |- + (?xi: + ^ \s* // .*? -\*- .*? \bjson\.net\b .*? -\*- # editorconfig + ) + +######################################################################################################################## + +contexts: + +####[ Strings ]######################################################################################################### + + strings: + - meta_prepend: true + - include: datetime-string + + datetime-string: + + # for date strings of json.Net v4.5+ with an ISO Date + # like "2000-01-01T00:00:00Z" + - match: |- + (?x: + (\") + ( + \d{4} [-] \d{2} [-] \d{2} + [Tt] + \d{2} [:] \d{2} [:] \d{2} + (?: + Z | [-+] \d{1,2} (?: [:]\d{1,2})? + )? + ) + (\") + ) + scope: >- + meta.string.json-dotnet + string.quoted.double.datetime.json-dotnet + captures: + 1: punctuation.definition.string.begin.json-dotnet + 2: constant.other.timestamp.json-dotnet + 3: punctuation.definition.string.end.json-dotnet + + # for date strings (of the old discontinued format) erroneously containing + # double escapes like "\/Date(1234)\/" + - match: |- + (?x: + (\") + ( + (\\) + \/Date\( + \d+ + \) + (\\) + \/ + ) + (\") + ) + scope: >- + meta.string.json-dotnet + string.quoted.double.datetime.json-dotnet + captures: + 1: punctuation.definition.string.begin.json-dotnet + 2: constant.other.timestamp.json-dotnet + 3: invalid.illegal.double-escape.json-dotnet + 4: invalid.illegal.double-escape.json-dotnet + 5: punctuation.definition.string.end.json-dotnet + + # the old discontinued format like "/Date(1234)/" + - match: |- + (?x: + (\") + ( + \/Date\( + \d+ + \)\/ + ) + (\") + ) + scope: >- + meta.string.json-dotnet + string.quoted.double.datetime.json-dotnet + captures: + 1: punctuation.definition.string.begin.json-dotnet + 2: constant.other.timestamp.json-dotnet + 3: punctuation.definition.string.end.json-dotnet diff --git a/JSON/Main.sublime-menu b/JSON/Main.sublime-menu new file mode 100644 index 00000000000..fe6d5172c22 --- /dev/null +++ b/JSON/Main.sublime-menu @@ -0,0 +1,130 @@ +// Packages/JSON/Main.sublime-menu +// +// This file is being maintained at: +// https://github.com/sublimehq/Packages/blob/master/JSON/Main.sublime-menu + + +[ + { + "id": "preferences", + "children": + [ + { + "id": "package-settings", + "children": + [ + { + "caption": "JSON", + "children": + [ + { + "caption": "JSON", + "children": + [ + { + "caption": "Minify", + "command": "json_minify" + }, + { + "caption": "Prettify", + "command": "json_prettify" + }, + { "caption": "-" }, + { + "caption": "Automatically prettify before saving", + "command": "json_toggle_auto_prettify" + }, + { + "caption": "Settings - Syntax Specific", + "command": "edit_settings", + "args": + { + "base_file": "${packages}/JSON/JSON.sublime-settings", + "default": "{\n\t$0\n}\n" + } + }, + { "caption": "-" }, + { + "caption": "Documentation: Specs", + "command": "open_url", + "args": + { + "url": "https://www.json.org/json-en.html" + } + }, + { + "caption": "Documentation: RFC 7159", + "command": "open_url", + "args": + { + "url": "https://datatracker.ietf.org/doc/html/rfc7159" + } + }, + { + "caption": "Documentation: ECMA 404", + "command": "open_url", + "args": + { + "url": "https://www.ecma-international.org/publications-and-standards/standards/ecma-404/" + } + } + ] + }, + { + "caption": "JSONC (JSON with Comments)", + "children": + [ + { + "caption": "Minify", + "command": "jsonc_minify" + }, + { + "caption": "Prettify", + "command": "jsonc_prettify" + } + ] + }, + { + "caption": "JSON5", + "children": + [ + { + "caption": "Documentation: Specs", + "command": "open_url", + "args": + { + "url": "https://spec.json5.org/#summary-of-features" + } + } + ] + }, + { "caption": "-" }, + { + "caption": "Support", + "children": + [ + { + "caption": "Changelog (Packages/JSON)", + "command": "open_url", + "args": + { + "url": "https://github.com/sublimehq/Packages/commits/master/JSON" + } + }, + { + "caption": "Report a (JSON package) issue", + "command": "open_url", + "args": + { + "url": "https://github.com/sublimehq/Packages/issues" + } + } + ] + } + ] + } + ] + } + ] + } +] diff --git a/JSON/Symbol List.tmPreferences b/JSON/Symbol List.tmPreferences new file mode 100644 index 00000000000..22c59c8cf92 --- /dev/null +++ b/JSON/Symbol List.tmPreferences @@ -0,0 +1,14 @@ + + + + scope + source.json meta.mapping.key - (meta.mapping.value meta.mapping.key | meta.sequence.list meta.mapping.key) + settings + + showInSymbolList + 1 + showInIndexedSymbolList + 1 + + + diff --git a/JSON/main.py b/JSON/main.py new file mode 100644 index 00000000000..8ddf5603bdb --- /dev/null +++ b/JSON/main.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python +# coding: utf-8 + +# This file is being maintained at: +# https://github.com/sublimehq/Packages/blob/master/JSON/main.py + + +import sublime + +from .src import * + + +def plugin_loaded() -> None: + json_prettify.plugin_loaded() + + +def plugin_unloaded() -> None: + json_prettify.plugin_unloaded() diff --git a/JSON/src/__init__.py b/JSON/src/__init__.py new file mode 100644 index 00000000000..181339e8b50 --- /dev/null +++ b/JSON/src/__init__.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python +# coding: utf-8 + +# This file is being maintained at: +# https://github.com/sublimehq/Packages/blob/master/JSON/src/__init__.py + + +from .json_prettify import * +from .jsonc_prettify import * diff --git a/JSON/src/json_prettify.py b/JSON/src/json_prettify.py new file mode 100644 index 00000000000..87edd9af8e5 --- /dev/null +++ b/JSON/src/json_prettify.py @@ -0,0 +1,217 @@ +#!/usr/bin/env python +# coding: utf-8 + +# This file is being maintained at: +# https://github.com/sublimehq/Packages/blob/master/JSON/src/json_prettify.py + + +import sublime +import sublime_plugin + +from __future__ import annotations +import collections +import decimal +import json +from typing import ( + Union +) + + +PKG_NAME: str = __package__.split('.')[0] +settings: Union[sublime.Settings, None] = None +base_settings: str = 'JSON.sublime-settings' +base_scope: str = 'source.json - (source.json.json-dotnet | source.json.json5 | source.json.jsonc)' + + +def status_msg(msg: str = '') -> None: + if msg == '': return + sublime.status_message(f'{PKG_NAME}: {msg}') + + +def print_msg(msg_header: str = '', msg_body: str = '') -> None: + if msg_body == '': return + print(f'JSON: {msg_header}:\n\n{msg_body}\n\n') + + +def json2py(view: sublime.View) -> sublime.Value: + old_contents: str = view.substr( + x=whole_view(view) + ) + try: + return json.loads( # https://docs.python.org/3.8/library/json.html#json.loads + s=old_contents, + object_pairs_hook=collections.OrderedDict, + parse_float=decimal.Decimal + ) + except Exception as e: + print_msg( + msg_header='Conversion failed due to error:', + msg_body=f'{e}' + ) + return None + + +def whole_view(view: sublime.View) -> sublime.Region: + return sublime.Region( + a=0, + b=view.size() + ) + + +def is_json(view: sublime.View) -> bool: + return view.match_selector( + pt=0, + selector=base_scope + ) + + +def plugin_loaded(reload: bool = False) -> None: + try: + global settings + settings = sublime.load_settings(base_name=base_settings) + settings.clear_on_change(tag='reload') + settings.add_on_change( + tag='reload', + callback=lambda: plugin_loaded(reload=True) + ) + except Exception as e: + print_msg( + msg_header=f'Loading "{base_settings}" failed due to error', + msg_body=f'{e}' + ) + + if reload: + status_msg('Reloaded settings on change.') + + +def plugin_unloaded() -> None: + global settings + settings = None + + +class JsonToggleAutoPrettify(sublime_plugin.WindowCommand): + + _is_checked: bool = False + _key: str = 'json.auto_prettify' + + def __init__(self, window: sublime.Window) -> None: + self.window: sublime.Window = window + + try: + if settings is None: + return + self._is_checked = settings.get(key=self._key, default=False) + except Exception: + pass + + def run(self) -> None: + try: + global settings + if settings is None: + return + if self._is_checked: + settings.erase(key=self._key) # remove the override (true) of the default (false) + else: + settings.set(key=self._key, value=True) + sublime.save_settings(base_name=base_settings) + self._is_checked = not self._is_checked # toggle + except Exception: + pass + + def is_checked(self) -> bool: + return self._is_checked + + +class JsonAutoPrettifyListener(sublime_plugin.EventListener): + + _key: str = 'json.auto_prettify' + + def on_pre_save_async(self, view) -> None: + if not is_json(view): + return + if settings is None: + return + if not settings.get(key=self._key, default=False): + return + view.run_command(cmd='json_prettify') + + +class JsonPrettify(sublime_plugin.TextCommand): + + def run(self, edit_token: sublime.Edit) -> None: + """ + Attempt to prettify the current view's JSON contents. Print errors to + the console when it fails. + """ + + try: + json_as_python: sublime.Value = json2py(self.view) + if json_as_python is None: return + self.view.replace( + edit_token, + r=whole_view(self.view), + text=json.dumps( # https://docs.python.org/3.8/library/json.html#json.dumps + obj=json_as_python, + allow_nan=False, + indent=4, + sort_keys=True + ) + ) + status_msg('Prettified.') + except Exception as e: + print_msg( + msg_header='Conversion failed due to error', + msg_body=f'{e}' + ) + status_msg('Prettifying failed. See console for details.') + pass + + def is_enabled(self) -> bool: + return is_json(self.view) + + def is_visible(self) -> bool: + return is_json(self.view) + + def description(self) -> str: + return 'Prettify JSON' + + +class JsonMinify(sublime_plugin.TextCommand): + + def run(self, edit_token: sublime.Edit) -> None: + """ + Attempt to minify the current view's JSON contents. Print errors to + the console when it fails. + """ + + try: + json_as_python: sublime.Value = json2py(self.view) + if json_as_python is None: return + self.view.replace( + edit_token, + r=whole_view(self.view), + text=json.dumps( # https://docs.python.org/3.8/library/json.html#json.dumps + obj=json_as_python, + allow_nan=False, + indent=None, + separators=(',', ':'), + sort_keys=True + ) + ) + status_msg('Minified.') + except Exception as e: + print_msg( + msg_header='Conversion failed due to error', + msg_body=f'{e}' + ) + status_msg('Minifying failed. See console for details.') + pass + + def is_enabled(self) -> bool: + return is_json(self.view) + + def is_visible(self) -> bool: + return is_json(self.view) + + def description(self) -> str: + return 'Minify JSON' diff --git a/JSON/src/jsonc_prettify.py b/JSON/src/jsonc_prettify.py new file mode 100644 index 00000000000..40a4a3c5b3d --- /dev/null +++ b/JSON/src/jsonc_prettify.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python +# coding: utf-8 + +# This file is being maintained at: +# https://github.com/sublimehq/Packages/blob/master/JSON/src/jsonc_prettify.py + + +import sublime +import sublime_plugin + +from __future__ import annotations +import json + + +PKG_NAME: str = __package__.split('.')[0] +base_scope: str = 'source.json.jsonc' + + +def status_msg(msg: str = '') -> None: + if msg == '': return + sublime.status_message(f'{PKG_NAME}: {msg}') + + +def print_msg(msg_header: str = '', msg_body: str = '') -> None: + if msg_body == '': return + print(f'JSONC: {msg_header}:\n\n{msg_body}\n\n') + + +def json2py(view: sublime.View) -> sublime.Value: + old_contents: str = view.substr( + x=whole_view(view) + ) + return sublime.decode_value( + data=old_contents + ) + + +def whole_view(view: sublime.View) -> sublime.Region: + return sublime.Region( + a=0, + b=view.size() + ) + + +def is_jsonc(view: sublime.View) -> bool: + return view.match_selector( + pt=0, + selector=base_scope + ) + + +class JsoncPrettify(sublime_plugin.TextCommand): + + def run(self, edit_token: sublime.Edit, auto: bool = False) -> None: + """ + Attempt to prettify the current view's JSONC contents. Print errors to + the console when it fails. + """ + + try: + if not auto and not sublime.ok_cancel_dialog( + msg='Prettifying JSONC will remove included comments and trailing commas.', + ok_title='Continue', + title='JSONC: Prettify' # only shown on Windows + ): + return + json_as_python: sublime.Value = json2py(self.view) + self.view.replace( + edit_token, + r=whole_view(self.view), + text=json.dumps( # https://docs.python.org/3.8/library/json.html#json.dumps + obj=json_as_python, + allow_nan=False, + indent=4, + sort_keys=True + ) + ) + status_msg('Prettified.') + except Exception as e: + print_msg( + msg_header='Conversion failed due to error', + msg_body=f'{e}' + ) + status_msg('Prettifying failed. See console for details.') + pass + + def is_enabled(self) -> bool: + return is_jsonc(self.view) + + def is_visible(self) -> bool: + return is_jsonc(self.view) + + def description(self) -> str: + return 'Prettify JSONC' + + +class JsoncMinify(sublime_plugin.TextCommand): + + def run(self, edit_token: sublime.Edit, auto: bool = False) -> None: + """ + Attempt to minify the current view's JSONC contents. Print errors to + the console when it fails. + """ + + try: + if not auto and not sublime.ok_cancel_dialog( + msg='Minifying JSONC will remove included comments and trailing commas.', + ok_title='Continue', + title='JSONC: Minify' # only shown on Windows + ): + return + json_as_python: sublime.Value = json2py(self.view) + self.view.replace( + edit_token, + r=whole_view(self.view), + text=json.dumps( # https://docs.python.org/3.8/library/json.html#json.dumps + obj=json_as_python, + allow_nan=False, + indent=None, + separators=(',', ':'), + sort_keys=True + ) + ) + status_msg('Minified.') + except Exception as e: + print_msg( + msg_header='Conversion failed due to error', + msg_body=f'{e}' + ) + status_msg('Minifying failed. See console for details.') + pass + + def is_enabled(self) -> bool: + return is_jsonc(self.view) + + def is_visible(self) -> bool: + return is_jsonc(self.view) + + def description(self) -> str: + return 'Minify JSONC' diff --git a/JSON/syntax_test_json.json b/JSON/syntax_test_json.json deleted file mode 100644 index ae0760eb3fb..00000000000 --- a/JSON/syntax_test_json.json +++ /dev/null @@ -1,123 +0,0 @@ -// SYNTAX TEST "Packages/JSON/JSON.sublime-syntax" - -{ -// <- meta.mapping.json punctuation.section.mapping.begin.json - "bool": false, -//^^^^^^ meta.mapping.key.json -//^^^^^^^^^^^^^^ - meta.mapping meta.mapping -// ^^^^^ constant.language.boolean.json - - "null": null, -//^^^^^^ meta.mapping.key.json -//^^^^^^^^^^^^^ - meta.mapping meta.mapping -// ^^^^ constant.language.null.json - - "dict": { "key": "value" } -// ^^^^^^^^^^^^^^^^^^ meta.mapping.value.json meta.mapping - meta.mapping meta.mapping meta.mapping -// ^ punctuation.section.mapping.begin.json -// ^ punctuation.section.mapping.end.json -// ^^ meta.mapping.value.json meta.mapping.json -// ^^^^^ meta.mapping.key.json string.quoted.double.json -// ^^ meta.mapping.value.json meta.mapping.json -// ^^^^^^^ meta.mapping.value.json meta.mapping.value.json string.quoted.double.json -// ^^ meta.mapping.value.json meta.mapping.json - -, , -// <- punctuation.separator.sequence.json -//^ invalid.illegal.expected-mapping-key.json - - "sep": {}, -// ^ punctuation.separator.key-value.json - - "array": [ /**/ ], -// ^^^^^^^^ meta.mapping.value.json meta.sequence.json -// ^ punctuation.section.sequence.begin.json -// ^^^^ comment.block.json -// ^ punctuation.section.sequence.end.json - - "dict": {"foo": }, -// ^ invalid.illegal.expected-mapping-value.json -// ^ punctuation.section.mapping.end.json - "dict": {"foo": - }, -//^ invalid.illegal.expected-mapping-value.json -// ^ punctuation.section.mapping.end.json - - "dict": {"foo"/*comment*/:/*comment*/"bar"/*comment*/}, -// ^^^^^^^^^^^ comment.block.json -// ^^^^^^^^^^^ comment.block.json -// ^^^^^^^^^^^ comment.block.json - - "dict": { - "foo": "bar" - // comment -// ^ - invalid -// ^^^^^^^^^^ comment.line.double-slash.js - , -// ^ punctuation.separator.sequence.json - "foo": "bar" - /* comment */ -// ^ - invalid -// ^^^^^^^^^^^^^ comment.block.json - }, -//^ punctuation.section.mapping.end.json -// ^ punctuation.separator.sequence.json - - "string": "string", -// ^ punctuation.definition.string.begin.json -// ^^^^^^^^ meta.mapping.value.json string.quoted.double.json -// ^ punctuation.definition.string.end.json - - "num": 20.09, -// ^^^^^ meta.number.float.decimal.json constant.numeric.value.json -// ^ punctuation.separator.decimal.json - - "neg": -9, -// ^^ meta.number.integer.decimal.json -// ^ keyword.operator.arithmetic.json -// ^ constant.numeric.value.json - - "E": 20e10, -// ^^^^^ meta.number.float.decimal.json constant.numeric.value.json -//^^^ meta.mapping.key.json string.quoted.double.json -// ^ punctuation.separator.key-value.json - meta.mapping.key - - "escape": "\n", -// ^^ constant.character.escape.json -// ^^^^ meta.mapping.value.json string.quoted.double.json - meta.mapping.key - - "illegal": "\.", -// ^^ invalid.illegal.unrecognized-string-escape.json - - "unterminated string -//^^^^^^^^^^^^^^^^^^^^ string.quoted.double.json -// ^ string.quoted.double.json invalid.illegal.unclosed-string.json - -// <- - string - -/**/: "test", -// ^ meta.mapping.json comment.block.json -// ^ punctuation.separator.key-value.json - comment -// ^^^^^^ meta.mapping.value.json string.quoted.double.json - - "array2": - [ - "foobar", -// ^^^^^^^^ meta.mapping.value meta.sequence.json string.quoted.double.json - meta.mapping.key - ] - - [], -//^ invalid.illegal.expected-mapping-separator.json -// ^^^ invalid.illegal.expected-mapping-key.json - - "typing json": {} - ,,,, "another key": false, - - "ke//y": "value" -//^^^^^^^ meta.mapping.key.json string.quoted.double.json - comment - -/** - * -// ^ meta.mapping.json comment.block.documentation.json punctuation.definition.comment.json -*/ -} diff --git a/Markdown/Markdown.sublime-syntax b/Markdown/Markdown.sublime-syntax index 64ee99ad7b7..fd47d68c828 100644 --- a/Markdown/Markdown.sublime-syntax +++ b/Markdown/Markdown.sublime-syntax @@ -910,7 +910,9 @@ contexts: - include: fenced-html - include: fenced-java - include: fenced-javascript + - include: fenced-json5 - include: fenced-jsonc + - include: fenced-json - include: fenced-jspx - include: fenced-jsx - include: fenced-lisp @@ -1258,11 +1260,49 @@ contexts: 0: meta.code-fence.definition.end.javascript.markdown-gfm 1: punctuation.definition.raw.code-fence.end.markdown + fenced-json5: + - match: |- + (?x) + {{fenced_code_block_start}} + ((?i:json5)) + {{fenced_code_block_trailing_infostring_characters}} + captures: + 0: meta.code-fence.definition.begin.json5.markdown-gfm + 2: punctuation.definition.raw.code-fence.begin.markdown + 5: constant.other.language-name.markdown + embed: scope:source.json.json5 + embed_scope: + markup.raw.code-fence.json5.markdown-gfm + source.json.json5 + escape: '{{fenced_code_block_escape}}' + escape_captures: + 0: meta.code-fence.definition.end.json5.markdown-gfm + 1: punctuation.definition.raw.code-fence.end.markdown + fenced-jsonc: - match: |- (?x) {{fenced_code_block_start}} - ((?i:jsonc?)) + ((?i:jsonc)) + {{fenced_code_block_trailing_infostring_characters}} + captures: + 0: meta.code-fence.definition.begin.jsonc.markdown-gfm + 2: punctuation.definition.raw.code-fence.begin.markdown + 5: constant.other.language-name.markdown + embed: scope:source.json.jsonc + embed_scope: + markup.raw.code-fence.jsonc.markdown-gfm + source.json.jsonc + escape: '{{fenced_code_block_escape}}' + escape_captures: + 0: meta.code-fence.definition.end.jsonc.markdown-gfm + 1: punctuation.definition.raw.code-fence.end.markdown + + fenced-json: + - match: |- + (?x) + {{fenced_code_block_start}} + ((?i:json)) {{fenced_code_block_trailing_infostring_characters}} captures: 0: meta.code-fence.definition.begin.json.markdown-gfm diff --git a/Markdown/tests/syntax_test_markdown.md b/Markdown/tests/syntax_test_markdown.md index d7e6ec89173..d9f6b9b9b52 100644 --- a/Markdown/tests/syntax_test_markdown.md +++ b/Markdown/tests/syntax_test_markdown.md @@ -1862,6 +1862,27 @@ for (var i = 0; i < 10; i++) { | <- meta.code-fence.definition.end.jsx.markdown-gfm punctuation.definition.raw.code-fence.end.markdown |^^ meta.code-fence.definition.end.jsx.markdown-gfm punctuation.definition.raw.code-fence.end.markdown +```json5 + +| <- markup.raw.code-fence.json5.markdown-gfm +``` +| <- meta.code-fence.definition.end.json5.markdown-gfm punctuation.definition.raw.code-fence.end.markdown +|^^ meta.code-fence.definition.end.json5.markdown-gfm punctuation.definition.raw.code-fence.end.markdown + +```jsonc + +| <- markup.raw.code-fence.jsonc.markdown-gfm +``` +| <- meta.code-fence.definition.end.jsonc.markdown-gfm punctuation.definition.raw.code-fence.end.markdown +|^^ meta.code-fence.definition.end.jsonc.markdown-gfm punctuation.definition.raw.code-fence.end.markdown + +```json + +| <- markup.raw.code-fence.json.markdown-gfm +``` +| <- meta.code-fence.definition.end.json.markdown-gfm punctuation.definition.raw.code-fence.end.markdown +|^^ meta.code-fence.definition.end.json.markdown-gfm punctuation.definition.raw.code-fence.end.markdown + ```lisp | <- markup.raw.code-fence.lisp.markdown-gfm source.lisp diff --git a/Perl/Perl.sublime-syntax b/Perl/Perl.sublime-syntax index 954cdeba3a4..c0fb678dab2 100644 --- a/Perl/Perl.sublime-syntax +++ b/Perl/Perl.sublime-syntax @@ -251,6 +251,18 @@ contexts: embed: scope:source.js embed_scope: source.js.embedded.perl escape: (?=^{{pod}}) + # embedded json5 + - match: \bjson5\b + scope: constant.other.language-name.json5.perl + embed: scope:source.json.json5 + embed_scope: source.json5.embedded.perl + escape: (?=^{{pod}}) + # embedded jsonc + - match: \bjsonc\b + scope: constant.other.language-name.jsonc.perl + embed: scope:source.json.jsonc + embed_scope: source.jsonc.embedded.perl + escape: (?=^{{pod}}) # embedded json - match: \bjson\b scope: constant.other.language-name.json.perl @@ -930,6 +942,22 @@ contexts: 3: entity.name.tag.heredoc.js.perl 4: punctuation.definition.tag.end.perl set: [string-heredoc-javascript, string-heredoc-expr] + # embedded json5 + - match: \s*((['"]?)(\s*JSON5)(\2)) + captures: + 1: meta.tag.heredoc.perl + 2: punctuation.definition.tag.begin.perl + 3: entity.name.tag.heredoc.json5.perl + 4: punctuation.definition.tag.end.perl + set: [string-heredoc-json5, string-heredoc-expr] + # embedded jsonc + - match: \s*((['"]?)(\s*JSONC)(\2)) + captures: + 1: meta.tag.heredoc.perl + 2: punctuation.definition.tag.begin.perl + 3: entity.name.tag.heredoc.jsonc.perl + 4: punctuation.definition.tag.end.perl + set: [string-heredoc-jsonc, string-heredoc-expr] # embedded json - match: \s*((['"]?)(\s*JSON)(\2)) captures: @@ -1013,6 +1041,24 @@ contexts: embed: scope:source.js escape: (?=^ *JAVASCRIPT$) + string-heredoc-json5: + - meta_content_scope: source.json5.embedded.perl + - match: ^\3$ + scope: meta.tag.heredoc.perl entity.name.tag.heredoc.json5.perl + pop: true + - match: '' + embed: scope:source.json.json5 + escape: (?=^ *JSON5$) + + string-heredoc-jsonc: + - meta_content_scope: source.jsonc.embedded.perl + - match: ^\3$ + scope: meta.tag.heredoc.perl entity.name.tag.heredoc.jsonc.perl + pop: true + - match: '' + embed: scope:source.json.jsonc + escape: (?=^ *JSONC$) + string-heredoc-json: - meta_content_scope: source.json.embedded.perl - match: ^\3$ diff --git a/Perl/syntax_test_perl.pl b/Perl/syntax_test_perl.pl index ba96ed7b8b3..44ea4a7e016 100644 --- a/Perl/syntax_test_perl.pl +++ b/Perl/syntax_test_perl.pl @@ -112,18 +112,38 @@ =head1 B<--param> # <- meta.comment.perl meta.interpolation.perl entity.name.tag.pod.perl #^^^ meta.comment.perl meta.interpolation.perl entity.name.tag.pod.perl +=begin json5 +# <- meta.comment.perl meta.interpolation.perl entity.name.tag.pod.perl +#^^^^^^^^^^ meta.comment.perl meta.interpolation.perl +#^^^^^ entity.name.tag.pod.perl +# ^ - constant - entity +# ^^^^ constant.other.language-name.json5.perl + +# <- meta.comment.perl meta.interpolation.perl source.json5.embedded.perl source.json.json5 +=end +# <- meta.comment.perl meta.interpolation.perl entity.name.tag.pod.perl +#^^^ meta.comment.perl meta.interpolation.perl entity.name.tag.pod.perl + +=begin jsonc +# <- meta.comment.perl meta.interpolation.perl entity.name.tag.pod.perl +#^^^^^^^^^^ meta.comment.perl meta.interpolation.perl +#^^^^^ entity.name.tag.pod.perl +# ^ - constant - entity +# ^^^^ constant.other.language-name.jsonc.perl + +# <- meta.comment.perl meta.interpolation.perl source.jsonc.embedded.perl source.json.jsonc +=end +# <- meta.comment.perl meta.interpolation.perl entity.name.tag.pod.perl +#^^^ meta.comment.perl meta.interpolation.perl entity.name.tag.pod.perl + =begin json # <- meta.comment.perl meta.interpolation.perl entity.name.tag.pod.perl #^^^^^^^^^^ meta.comment.perl meta.interpolation.perl #^^^^^ entity.name.tag.pod.perl # ^ - constant - entity # ^^^^ constant.other.language-name.json.perl - { -# ^ meta.comment.perl meta.interpolation.perl source.json.embedded.perl source.json - "key": "value", -# ^^^^^^^^^^^^^^^ meta.comment.perl meta.interpolation.perl source.json.embedded.perl source.json - } -# ^ meta.comment.perl meta.interpolation.perl source.json.embedded.perl source.json + +# <- meta.comment.perl meta.interpolation.perl source.json.embedded.perl source.json =end # <- meta.comment.perl meta.interpolation.perl entity.name.tag.pod.perl #^^^ meta.comment.perl meta.interpolation.perl entity.name.tag.pod.perl