From 1034e6d0e7d10fce546d15f79d6a8350995a57f3 Mon Sep 17 00:00:00 2001 From: James Saryerwinnie Date: Thu, 30 Mar 2023 01:28:13 -0400 Subject: [PATCH] Remove sphinx docs from repo 1. We haven't been publishing the docs anywhere for years 2. There's no CI or automation that builds the docs 3. The docs contents are outdated, they previously contained proposals which now have their own dedicated repo. --- docs/Makefile | 153 --- docs/conf.py | 97 -- docs/index.rst | 34 - docs/proposals.rst | 16 - docs/proposals/array-slices.rst | 109 -- docs/proposals/exptype.rst | 273 ---- docs/proposals/filter-expressions.rst | 260 ---- docs/proposals/functions.rst | 707 ---------- docs/proposals/improved-identifiers.rst | 234 ---- docs/proposals/nested-expressions.rst | 221 ---- docs/proposals/pipes.rst | 200 --- docs/specification.rst | 1615 ----------------------- requirements-docs.txt | 3 - scripts/bumpversion | 16 - scripts/release | 7 +- 15 files changed, 1 insertion(+), 3944 deletions(-) delete mode 100644 docs/Makefile delete mode 100644 docs/conf.py delete mode 100644 docs/index.rst delete mode 100644 docs/proposals.rst delete mode 100644 docs/proposals/array-slices.rst delete mode 100644 docs/proposals/exptype.rst delete mode 100644 docs/proposals/filter-expressions.rst delete mode 100644 docs/proposals/functions.rst delete mode 100644 docs/proposals/improved-identifiers.rst delete mode 100644 docs/proposals/nested-expressions.rst delete mode 100644 docs/proposals/pipes.rst delete mode 100644 docs/specification.rst delete mode 100644 requirements-docs.txt diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index fd63973b..00000000 --- a/docs/Makefile +++ /dev/null @@ -1,153 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = _build - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - -rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/JamesPath.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/JamesPath.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/JamesPath" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/JamesPath" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index 79d9e57a..00000000 --- a/docs/conf.py +++ /dev/null @@ -1,97 +0,0 @@ -# -*- coding: utf-8 -*- -import guzzle_sphinx_theme - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ----------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'JMESPath' -copyright = u'2014, James Saryerwinnie' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = '0.8' -# The full version, including alpha/beta/rc tags. -release = '1.0.1' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'guzzle_sphinx_theme.GuzzleStyle' - -html_translator_class = 'guzzle_sphinx_theme.HTMLTranslator' -html_theme_path = guzzle_sphinx_theme.html_theme_path() -html_theme = 'guzzle_sphinx_theme' -extensions.append("guzzle_sphinx_theme") - - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -html_theme_options = html_theme_options = { - # Set the name of the project to appear in the nav menu - "project_nav_name": "JMESPath", - - # Set your GitHub user and repo to enable GitHub stars links - "github_user": "boto", - "github_repo": "jmespath", - - # Set to true to bind left and right key events to turn the page - "bind_key_events": 1, -} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Output file base name for HTML help builder. -htmlhelp_basename = 'JMESPathdoc' diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index a9dac50a..00000000 --- a/docs/index.rst +++ /dev/null @@ -1,34 +0,0 @@ -.. JamesPath documentation master file, created by - sphinx-quickstart on Tue Feb 19 14:49:37 2013. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -JMESPath -======== - -JSON Matching Expression paths. JMESPath allows you -to declaratively specify how to extract elements from a JSON document. - -For example, given this document:: - - {"foo": {"bar": "baz"}} - -The jmespath expression ``foo.bar`` will return "baz". - - -Contents: - -.. toctree:: - :maxdepth: 2 - - specification - proposals - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - diff --git a/docs/proposals.rst b/docs/proposals.rst deleted file mode 100644 index c09c1483..00000000 --- a/docs/proposals.rst +++ /dev/null @@ -1,16 +0,0 @@ -================== -JMESPath Proposals -================== - -This document lists all of the proposed JMESPath syntax and functionality -changes. Proposals are marked as either "draft", "accepted", or "rejected". - -.. toctree:: - :maxdepth: 1 - - proposals/nested-expressions - proposals/improved-identifiers - proposals/filter-expressions - proposals/pipes - proposals/functions - proposals/exptype diff --git a/docs/proposals/array-slices.rst b/docs/proposals/array-slices.rst deleted file mode 100644 index 7a67dcbc..00000000 --- a/docs/proposals/array-slices.rst +++ /dev/null @@ -1,109 +0,0 @@ -======================= -Array Slice Expressions -======================= - -:JEP: 5 -:Author: Michael Dowling -:Status: draft -:Created: 08-Dec-2013 - -Abstract -======== - -This document proposes modifying the JMESPath grammar to support array slicing -for accessing specific portions of an array. - -Motivation -========== - -The current JMESPath grammar does not allow plucking out specific portions of -an array. - -The following examples are possible with array slicing notation utilizing an -optional start position, optional stop position, and optional step that can be -less than or greater than 0: - -1. Extracting every N indices (e.g., only even ``[::2]``, only odd ``[1::2]``, - etc) -2. Extracting only elements after a given start position: ``[2:]`` -3. Extracting only elements before a given stop position: ``[:5]`` -4. Extracting elements between a given start and end position: ``[2::5]`` -5. Only the last 5 elements: ``[-5:]`` -6. The last five elements in reverse order: ``[:-5:-1]`` -7. Reversing the order of an array: ``[::-1]`` - -Syntax -====== - -This syntax introduces Python style array slicing that allows a start position, -stop position, and step. This syntax also proposes following the same semantics -as python slices. - -:: - - [start:stop:step] - -Each part of the expression is optional. You can omit the start position, stop -position, or step. No more than three values can be provided in a slice -expression. - -The step value determines how my indices to skip after each element is plucked -from the array. A step of 1 (the default step) will not skip any indices. A -step value of 2 will skip every other index while plucking values from an -array. A step value of -1 will extract values in reverse order from the array. -A step value of -2 will extract values in reverse order from the array while, -skipping every other index. - -Slice expressions adhere to the following rules: - -1. If a negative start position is given, it is calculated as the total length - of the array plus the given start position. -2. If no start position is given, it is assumed to be 0 if the given step is - greater than 0 or the end of the array if the given step is less than 0. -3. If a negative stop position is given, it is calculated as the total length - of the array plus the given stop position. -4. If no stop position is given, it is assumed to be the length of the array if - the given step is greater than 0 or 0 if the given step is less than 0. -5. If the given step is omitted, it it assumed to be 1. -6. If the given step is 0, an error must be raised. -7. If the element being sliced is not an array, the result must be ``null``. -8. If the element being sliced is an array and yields no results, the result - must be an empty array. - - -Modified Grammar -================ - -The following modified JMESPath grammar supports array slicing. - -:: - - expression = sub-expression / index-expression / or-expression / identifier / "*" - expression =/ multi-select-list / multi-select-hash - sub-expression = expression "." expression - or-expression = expression "||" expression - index-expression = expression bracket-specifier / bracket-specifier - multi-select-list = "[" ( expression *( "," expression ) ) "]" - multi-select-hash = "{" ( keyval-expr *( "," keyval-expr ) ) "}" - keyval-expr = identifier ":" expression - bracket-specifier = "[" (number / "*" / slice-expression) "]" / "[]" - slice-expression = ":" - slice-expression =/ number ":" number ":" number - slice-expression =/ number ":" - slice-expression =/ number ":" ":" number - slice-expression =/ ":" number - slice-expression =/ ":" number ":" number - slice-expression =/ ":" ":" number - number = [-]1*digit - digit = "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" / "0" - identifier = 1*char - identifier =/ quote 1*(unescaped-char / escaped-quote) quote - escaped-quote = escape quote - unescaped-char = %x30-10FFFF - escape = %x5C ; Back slash: \ - quote = %x22 ; Double quote: '"' - char = %x30-39 / ; 0-9 - %x41-5A / ; A-Z - %x5F / ; _ - %x61-7A / ; a-z - %x7F-10FFFF diff --git a/docs/proposals/exptype.rst b/docs/proposals/exptype.rst deleted file mode 100644 index ba90eae0..00000000 --- a/docs/proposals/exptype.rst +++ /dev/null @@ -1,273 +0,0 @@ -================ -Expression Types -================ - -:JEP: 8 -:Author: James Saryerwinnie -:Status: accepted -:Created: 02-Mar-2013 - -Abstract -======== - -This JEP proposes grammar modifications to JMESPath to allow for -expression references within functions. This allows for functions -such as ``sort_by``, ``max_by``, ``min_by``. These functions take -an argument that resolves to an expression type. This enables -functionality such as sorting an array based on an expression that -is evaluated against every array element. - - -Motivation -========== - -A useful feature that is common in other expression languages is the -ability to sort a JSON object based on a particular key. For example, -given a JSON object: - -.. code:: json - - { - "people": [ - {"age": 20, "age_str": "20", "bool": true, "name": "a", "extra": "foo"}, - {"age": 40, "age_str": "40", "bool": false, "name": "b", "extra": "bar"}, - {"age": 30, "age_str": "30", "bool": true, "name": "c"}, - {"age": 50, "age_str": "50", "bool": false, "name": "d"}, - {"age": 10, "age_str": "10", "bool": true, "name": 3} - ] - } - -It is not currently possible to sort the ``people`` array by the ``age`` key. -Also, ``sort`` is not defined for the ``object`` type, so it's not currently -possible to even sort the ``people`` array. In order to sort the ``people`` array, -we need to know what key to use when sorting the array. - -This concept of sorting based on a key can be generalized. Instead of -requiring a key name, an expression can be provided that each element -would be evaluated against. In the simplest case, this expression would just -be an ``identifier``, but more complex expressions could be used such as -``foo.bar.baz``. - -A simple way to accomplish this might be to create a function like this: - -.. code:: python - - sort_by(array arg1, expression) - - # Called like: - - sort_by(people, age) - sort_by(people, to_number(age_str)) - -However, there's a problem with the ``sort_by`` function as defined above. -If we follow the function argument resolution process we get: - -.. code:: python - - sort_by(people, age) - - # 1. resolve people - arg1 = search(people, ) -> [{"age": ...}, {...}] - - # 2. resolve age - arg2 = search(age, ) -> null - - sort_by([{"age": ...}, {...}], null) - -The second argument is evaluated against the current node and the expression -``age`` will resolve to ``null`` because the input data has no ``age`` key. -There needs to be some way to specify that an expression should evaluate to -an expression type:: - - arg = search(, ) -> - -Then the function definition of ``sort_by`` would be:: - - sort_by(array arg1, expression arg2) - - -Specification -============= - -The following grammar rules will be updated to:: - - function-arg = expression / - current-node / - "&" expression - -Evaluating an expression reference should return an object of type -"expression". The list of data types supported by a function will now be: - -* number (integers and double-precision floating-point format in JSON) -* string -* boolean (``true`` or ``false``) -* array (an ordered, sequence of values) -* object (an unordered collection of key value pairs) -* null -* expression (denoted by ``&expression``) - -Function signatures can now be specified using this new ``expression`` type. -Additionally, a function signature can specify the return type of the -expression. Similarly how arrays can specify a type within a list using the -``array[type]`` syntax, expressions can specify their resolved type using -``expression->type`` syntax. - -Note that any valid expression is allowed after ``&``, so the following -expressions are valid: - -.. code:: python - - sort_by(people, &foo.bar.baz) - sort_by(people, &foo.bar[0].baz) - sort_by(people, &to_number(foo[0].bar)) - - -Additional Functions --------------------- - -The following functions will be added: - -sort_by -~~~~~~~ - -:: - - sort_by(array elements, expression->number|expression->string expr) - -Sort an array using an expression ``expr`` as the sort key. -Below are several examples using the ``people`` array (defined above) as the -given input. ``sort_by`` follows the same sorting logic as the ``sort`` -function. - - -.. list-table:: Examples - :header-rows: 1 - - * - Expression - - Result - * - ``sort_by(people, &age)[].age`` - - [10, 20, 30, 40, 50] - * - ``sort_by(people, &age)[0]`` - - {"age": 10, "age_str": "10", "bool": true, "name": 3} - * - ``sort_by(people, &to_number(age_str))[0]`` - - {"age": 10, "age_str": "10", "bool": true, "name": 3} - - -max_by -~~~~~~ - -:: - - max_by(array elements, expression->number expr) - -Return the maximum element in an array using the expression ``expr`` as the -comparison key. The entire maximum element is returned. -Below are several examples using the ``people`` array (defined above) as the -given input. - - -.. list-table:: Examples - :header-rows: 1 - - * - Expression - - Result - * - ``max_by(people, &age)`` - - {"age": 50, "age_str": "50", "bool": false, "name": "d"}, - * - ``max_by(people, &age).age`` - - 50 - * - ``max_by(people, &to_number(age_str))`` - - {"age": 50, "age_str": "50", "bool": false, "name": "d"}, - * - ``max_by(people, &age_str)`` - - - * - ``max_by(people, age)`` - - - - -min_by -~~~~~~ - -:: - - min_by(array elements, expression->number expr) - -Return the minimum element in an array using the expression ``expr`` as the -comparison key. The entire maximum element is returned. -Below are several examples using the ``people`` array (defined above) as the -given input. - - -.. list-table:: Examples - :header-rows: 1 - - * - Expression - - Result - * - ``min_by(people, &age)`` - - {"age": 10, "age_str": "10", "bool": true, "name": 3} - * - ``min_by(people, &age).age`` - - 10 - * - ``min_by(people, &to_number(age_str))`` - - {"age": 10, "age_str": "10", "bool": true, "name": 3} - * - ``min_by(people, &age_str)`` - - - * - ``min_by(people, age)`` - - - - -Alternatives ------------- - -There were a number of alternative proposals considered. Below outlines -several of these alternatives. - -Logic in Argument Resolver -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The first proposed choice (which was originally in JEP-3 but later removed) was -to not have any syntactic construct for specifying functions, and to allow the -function signature to dictate whether or not an argument was resolved. The -signature for ``sort_by`` would be:: - - sort_by(array arg1, any arg2) - arg1 -> resolved - arg2 -> not resolved - -Then the argument resolver would introspect the argument specification of a -function to determine what to do. Roughly speaking, the pseudocode would be:: - - call-function(current-data) - arglist = [] - for each argspec in functions-argspec: - if argspect.should_resolve: - arglist <- resolve(argument, current-data) - else - arglist <- argument - type-check(arglist) - return invoke-function(arglist) - -However, there are several reasons not to do this: - -* This imposes a specific implementation. This implementation would be - challenging in a bytecode VM, as the CALL bytecode will typically - resolve arguments onto the stack and allow the function to then - pop arguments off the stack and perform its own arity validation. -* This deviates from the "standard" model of how functions are - traditionally implemented. - - -Specifying Expressions as Strings -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Another proposed alternative was to allow the expression to be -a string type and to give functions the capability to parse/eval -expressions. The ``sort_by`` function would look like this:: - - sort_by(people, `age`) - sort_by(people, `foo.bar.baz`) - -The main reasons this proposal was not chosen was because: - -* This complicates the implementations. For implementations that walk the AST - inline, this means AST nodes need access to the parser. For external tree - visitors, the visitor needs access to the parser. -* This moves what *could* by a compile time error into a run time error. The - evaluation of the expression string happens when the function is invoked. diff --git a/docs/proposals/filter-expressions.rst b/docs/proposals/filter-expressions.rst deleted file mode 100644 index ad13b840..00000000 --- a/docs/proposals/filter-expressions.rst +++ /dev/null @@ -1,260 +0,0 @@ -================== -Filter Expressions -================== - -:JEP: 7 -:Author: James Saryerwinnie -:Status: accepted -:Created: 16-Dec-2013 - - -Abstract -======== - -This JEP proposes grammar modifications to JMESPath to allow for filter -expressions. A filtered expression allows list elements to be selected -based on matching expressions. A literal expression -is also introduced (from JEP 3) so that it is possible to match elements -against literal values. - - -Motivation -========== - -A common request when querying JSON objects is the ability to select -elements based on a specific value. For example, given a JSON object:: - - {"foo": [{"state": "WA", "value": 1}, - {"state": "WA", "value": 2}, - {"state": "CA", "value": 3}, - {"state": "CA", "value": 4}]} - -A user may want to select all objects in the ``foo`` list that have -a ``state`` key of ``WA``. There is currently no way to do this -in JMESPath. This JEP will introduce a syntax that allows this:: - - foo[?state == `WA`] - -Additionally, a user may want to project additional expressions onto the values -matched from a filter expression. For example, given the data above, select -the ``value`` key from all objects that have a ``state`` of ``WA``:: - - foo[?state == `WA`].value - -would return ``[1, 2]``. - - -Specification -============= - -The updated grammar for filter expressions:: - - bracket-specifier = "[" (number / "*") "]" / "[]" - bracket-specifier =/ "[?" list-filter-expression "]" - list-filter-expression = expression comparator expression - comparator = "<" / "<=" / "==" / ">=" / ">" / "!=" - expression =/ literal - literal = "`" json-value "`" - literal =/ "`" 1*(unescaped-literal / escaped-literal) "`" - unescaped-literal = %x20-21 / ; space ! - %x23-5A / ; # - [ - %x5D-5F / ; ] ^ _ - %x61-7A ; a-z - %x7C-10FFFF ; |}~ ... - escaped-literal = escaped-char / (escape %x60) - -The ``json-value`` rule is any valid json value. While it's recommended -that implementations use an existing JSON parser to parse the -``json-value``, the grammar is added below for completeness:: - - json-value = "false" / "null" / "true" / json-object / json-array / - json-number / json-quoted-string - json-quoted-string = %x22 1*(unescaped-literal / escaped-literal) %x22 - begin-array = ws %x5B ws ; [ left square bracket - begin-object = ws %x7B ws ; { left curly bracket - end-array = ws %x5D ws ; ] right square bracket - end-object = ws %x7D ws ; } right curly bracket - name-separator = ws %x3A ws ; : colon - value-separator = ws %x2C ws ; , comma - ws = *(%x20 / ; Space - %x09 / ; Horizontal tab - %x0A / ; Line feed or New line - %x0D ; Carriage return - ) - json-object = begin-object [ member *( value-separator member ) ] end-object - member = quoted-string name-separator json-value - json-array = begin-array [ json-value *( value-separator json-value ) ] end-array - json-number = [ minus ] int [ frac ] [ exp ] - decimal-point = %x2E ; . - digit1-9 = %x31-39 ; 1-9 - e = %x65 / %x45 ; e E - exp = e [ minus / plus ] 1*DIGIT - frac = decimal-point 1*DIGIT - int = zero / ( digit1-9 *DIGIT ) - minus = %x2D ; - - plus = %x2B ; + - zero = %x30 ; 0 - - -Comparison Operators --------------------- - -The following operations are supported: - -* ``==``, tests for equality. -* ``!=``, tests for inequality. -* ``<``, less than. -* ``<=``, less than or equal to. -* ``>``, greater than. -* ``>=``, greater than or equal to. - -The behavior of each operation is dependent on the type of each evaluated -expression. - -The comparison semantics for each operator are defined below based on -the corresponding JSON type: - -Equality Operators -~~~~~~~~~~~~~~~~~~ - -For ``string/number/true/false/null`` types, equality is an exact match. A -``string`` is equal to another ``string`` if they they have the exact sequence -of code points. The literal values ``true/false/null`` are only equal to their -own literal values. Two JSON objects are equal if they have the same set -of keys (for each key in the first JSON object there exists a key with equal -value in the second JSON object). Two JSON arrays are equal if they have -equal elements in the same order (given two arrays ``x`` and ``y``, -for each ``i`` in ``x``, ``x[i] == y[i]``). - -Ordering Operators -~~~~~~~~~~~~~~~~~~ - -Ordering operators ``>, >=, <, <=`` are **only** valid for numbers. -Evaluating any other type with a comparison operator will yield a ``null`` -value, which will result in the element being excluded from the result list. -For example, given:: - - search('foo[?a "foobar" - `"foobar"` -> "foobar" - `123` -> 123 - `"123"` -> "123" - `123.foo` -> "123.foo" - `true` -> true - `"true"` -> "true" - `truee` -> "truee" - -Literal expressions aren't allowed on the right hand side of a subexpression:: - - foo[*].`literal` - -but they are allowed on the left hand side:: - - `{"foo": "bar"}`.foo - -They may also be included in other expressions outside of a filter expressions. -For example:: - - {value: foo.bar, type: `multi-select-hash`} - - -Rationale -========= - -The proposed filter expression syntax was chosen such that there is sufficient -expressive power for any type of filter one might need to perform while at the -same time being as minimal as possible. To help illustrate this, below are a -few alternate syntax that were considered. - -In the simplest case where one might filter a key based on a literal value, -a possible filter syntax would be:: - - foo[bar == baz] - -or in general terms: ``[identifier comparator literal-value]``. However this -has several issues: - -* It is not possible to filter based on two expressions (get all elements whose - ``foo`` key equals its ``bar`` key. -* The literal value is on the right hand side, making it hard to troubleshoot - if the identifier and literal value are swapped: ``foo[baz == bar]``. -* Without some identifying token unary filters would not be possible as they - would be ambiguous. Is the expression ``[foo]`` filtering all elements with - a foo key with a truth value or is it a multiselect-list selecting the - ``foo`` key from each hash? Starting a filter expression with a token such - as ``[?`` make it clear that this is a filter expression. -* This makes the syntax for filtering against literal JSON arrays and objects - hard to visually parse. "Filter all elements whose ``foo`` key is a single - list with a single integer value of 2: ``[foo == [2]]``. -* Adding literal expressions makes them useful even outside of a filter - expression. For example, in a ``multi-select-hash``, you can create - arbitrary key value pairs: ``{a: foo.bar, b: `some string`}``. - - -This JEP is purposefully minimal. There are several extensions that can be -added in future: - -* Support any arbitrary expression within the ``[? ... ]``. This would - enable constructs such as or expressions within a filter. This would - allow unary expressions. - -In order for this to be useful we need to define what corresponds to true and -false values, e.g. an empty list is a false value. Additionally, "or -expressions" would need to change its semantics to branch based on the -true/false value of an expression instead of whether or not the expression -evaluates to null. - -This is certainly a direction to take in the future, adding arbitrary -expressions in a filter would be a backwards compatible change, so it's not -part of this JEP. - -* Allow filter expressions as top level expressions. This would potentially - just return ``true/false`` for any value that it matched. - -This might be useful if you can combine this with something that can accept -a list to use as a mask for filtering other elements. diff --git a/docs/proposals/functions.rst b/docs/proposals/functions.rst deleted file mode 100644 index ab910be3..00000000 --- a/docs/proposals/functions.rst +++ /dev/null @@ -1,707 +0,0 @@ -========= -Functions -========= - -:JEP: 3 -:Author: Michael Dowling, James Saryerwinnie -:Status: Draft -:Created: 27-Nov-2013 - -Abstract -======== - -This document proposes modifying the -`JMESPath grammar `__ -to support function expressions. - -Motivation -========== - -Functions allow users to easily transform and filter data in JMESPath -expressions. As JMESPath is currently implemented, functions would be very useful -in ``multi-select-list`` and ``multi-select-hash`` expressions to format the -output of an expression to contain data that might not have been in the -original JSON input. Combined with filtered expressions, functions -would be a powerful mechanism to perform any kind of special comparisons for -things like ``length()``, ``contains()``, etc. - -Data Types -========== - -In order to support functions, a type system is needed. The JSON types are used: - -* number (integers and double-precision floating-point format in JSON) -* string -* boolean (``true`` or ``false``) -* array (an ordered, sequence of values) -* object (an unordered collection of key value pairs) -* null - -Syntax Changes -============== - -Functions are defined in the ``function-expression`` rule below. A function -expression is an ``expression`` itself, and is valid any place an -``expression`` is allowed. - -The grammar will require the following grammar additions: - -:: - - function-expression = identifier "(" *(function-arg *("," function-arg ) ) ")" - function-arg = expression / number / current-node - current-node = "@" - -``expression`` will need to be updated to add the ``function-expression`` production: - -:: - - expression = sub-expression / index-expression / or-expression / identifier / "*" - expression =/ multi-select-list / multi-select-hash - expression =/ literal / function-expression - -A function can accept any number of arguments, and each argument can be an -expression. Each function must define a signature that specifies the number -and allowed types of its expected arguments. Functions can be variadic. - - -current-node ------------- - -The ``current-node`` token can be used to represent the current node being -evaluated. The ``current-node`` token is useful for functions that require the -current node being evaluated as an argument. For example, the following -expression creates an array containing the total number of elements in the -``foo`` object followed by the value of ``foo["bar"]``. - -:: - - foo[].[count(@), bar] - -JMESPath assumes that all function arguments operate on the current node unless -the argument is a ``literal`` or ``number`` token. Because of this, an -expression such as ``@.bar`` would be equivalent to just ``bar``, so the -current node is only allowed as a bare expression. - - -current-node state -~~~~~~~~~~~~~~~~~~ - -At the start of an expression, the value of the current node is the data -being evaluated by the JMESPath expression. As an expression is evaluated, the -value the the current node represents MUST change to reflect the node currently -being evaluated. When in a projection, the current node value MUST be changed -to the node currently being evaluated by the projection. - - -Function Evaluation -=================== - -Functions are evaluated in applicative order. Each argument must be an -expression, each argument expression must be evaluated before evaluating the -function. The function is then called with the evaluated function arguments. -The result of the ``function-expression`` is the result returned by the -function call. If a ``function-expression`` is evaluated for a function that -does not exist, the JMESPath implementation must indicate to the caller that an -``unknown-function`` error occurred. How and when this error is raised is -implementation specific, but implementations should indicate to the caller that -this specific error occurred. - -Functions can either have a specific arity or be variadic with a minimum -number of arguments. If a ``function-expression`` is encountered where the -arity does not match or the minimum number of arguments for a variadic function -is not provided, then implementations must indicate to the caller than an -``invalid-arity`` error occurred. How and when this error is raised is -implementation specific. - -Each function signature declares the types of its input parameters. If any -type constraints are not met, implementations must indicate that an -``invalid-type`` error occurred. - -In order to accommodate type constraints, functions are provided to convert -types to other types (``to_string``, ``to_number``) which are defined below. -No explicit type conversion happens unless a user specifically uses one of -these type conversion functions. - -Function expressions are also allowed as the child element of a sub expression. -This allows functions to be used with projections, which can enable functions -to be applied to every element in a projection. For example, given the input -data of ``["1", "2", "3", "notanumber", true]``, the following expression can -be used to convert (and filter) all elements to numbers:: - - search([].to_number(@), ``["1", "2", "3", "notanumber", true]``) -> [1, 2, 3] - -This provides a simple mechanism to explicitly convert types when needed. - - -Built-in Functions -================== - -JMESPath has various built-in functions that operate on different -data types, documented below. Each function below has a signature -that defines the expected types of the input and the type of the returned -output:: - - return_type function_name(type $argname) - return_type function_name2(type1|type2 $argname) - -If a function can accept multiple types for an input value, then the -multiple types are separated with ``|``. If the resolved arguments do not -match the types specified in the signature, an ``invalid-type`` error occurs. - -The ``array`` type can further specify requirements on the type of the elements -if they want to enforce homogeneous types. The subtype is surrounded by -``[type]``, for example, the function signature below requires its input -argument resolves to an array of numbers:: - - return_type foo(array[number] $argname) - -As a shorthand, the type ``any`` is used to indicate that the argument can be -of any type (``array|object|number|string|boolean|null``). - -The first function below, ``abs`` is discussed in detail to demonstrate the -above points. Subsequent function definitions will not include these details -for brevity, but the same rules apply. - -.. note:: - - All string related functions are defined on the basis of Unicode code - points; they do not take normalization into account. - - -abs ---- - -:: - - number abs(number $value) - -Returns the absolute value of the provided argument. The signature indicates -that a number is returned, and that the input argument ``$value`` **must** -resolve to a number, otherwise a ``invalid-type`` error is triggered. - -Below is a worked example. Given:: - - {"foo": -1, "bar": "2"} - -Evaluating ``abs(foo)`` works as follows: - -1. Evaluate the input argument against the current data:: - - search(foo, {"foo": -11, "bar": 2"}) -> -1 - -2. Validate the type of the resolved argument. In this case - ``-1`` is of type ``number`` so it passes the type check. - -3. Call the function with the resolved argument:: - - abs(-1) -> 1 - -4. The value of ``1`` is the resolved value of the function expression - ``abs(foo)``. - - -Below is the same steps for evaluating ``abs(bar)``: - -1. Evaluate the input argument against the current data:: - - search(foo, {"foo": -1, "bar": 2"}) -> "2" - -2. Validate the type of the resolved argument. In this case - ``"2`` is of type ``string`` so the immediate indicate that - an ``invalid-type`` error occurred. - - -As a final example, here is the steps for evaluating ``abs(to_number(bar))``: - -1. Evaluate the input argument against the current data:: - - search(to_number(bar), {"foo": -1, "bar": "2"}) - -2. In order to evaluate the above expression, we need to evaluate - ``to_number(bar)``:: - - search(bar, {"foo": -1, "bar": "2"}) -> "2" - # Validate "2" passes the type check for to_number, which it does. - to_number("2") -> 2 - -3. Now we can evaluate the original expression:: - - search(to_number(bar), {"foo": -1, "bar": "2"}) -> 2 - -4. Call the function with the final resolved value:: - - abs(2) -> 2 - -5. The value of ``2`` is the resolved value of the function expression - ``abs(to_number(bar))``. - - -.. list-table:: Examples - :header-rows: 1 - - * - Expression - - Result - * - ``abs(1)`` - - 1 - * - ``abs(-1)`` - - 1 - * - ``abs(`abc`)`` - - ```` - - -avg ---- - -:: - - number avg(array[number] $elements) - -Returns the average of the elements in the provided array. - -An empty array will produce a return value of null. - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``[10, 15, 20]`` - - ``avg(@)`` - - 15 - * - ``[10, false, 20]`` - - ``avg(@)`` - - ```` - * - ``[false]`` - - ``avg(@)`` - - ```` - * - ``false`` - - ``avg(@)`` - - ```` - - -contains --------- - -:: - - boolean contains(array|string $subject, array|object|string|number|boolean $search) - -Returns ``true`` if the given ``$subject`` contains the provided ``$search`` -string. - -If ``$subject`` is an array, this function returns true if one of the elements -in the array is equal to the provided ``$search`` value. - -If the provided ``$subject`` is a string, this function returns true if -the string contains the provided ``$search`` argument. - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - n/a - - ``contains(`foobar`, `foo`)`` - - ``true`` - * - n/a - - ``contains(`foobar`, `not`)`` - - ``false`` - * - n/a - - ``contains(`foobar`, `bar`)`` - - ``true`` - * - n/a - - ``contains(`false`, `bar`)`` - - ```` - * - n/a - - ``contains(`foobar`, 123)`` - - ``false`` - * - ``["a", "b"]`` - - ``contains(@, `a`)`` - - ``true`` - * - ``["a"]`` - - ``contains(@, `a`)`` - - ``true`` - * - ``["a"]`` - - ``contains(@, `b`)`` - - ``false`` - -ceil ----- - -:: - - number ceil(number $value) - -Returns the next highest integer value by rounding up if necessary. - -.. list-table:: Examples - :header-rows: 1 - - * - Expression - - Result - * - ``ceil(`1.001`)`` - - 2 - * - ``ceil(`1.9`)`` - - 2 - * - ``ceil(`1`)`` - - 1 - * - ``ceil(`abc`)`` - - ``null`` - -floor ------ - -:: - - number floor(number $value) - -Returns the next lowest integer value by rounding down if necessary. - -.. list-table:: Examples - :header-rows: 1 - - * - Expression - - Result - * - ``floor(`1.001`)`` - - 1 - * - ``floor(`1.9`)`` - - 1 - * - ``floor(`1`)`` - - 1 - - -join ----- - -:: - - string join(string $glue, array[string] $stringsarray) - -Returns all of the elements from the provided ``$stringsarray`` array joined -together using the ``$glue`` argument as a separator between each. - - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``["a", "b"]`` - - ``join(`, `, @)`` - - "a, b" - * - ``["a", "b"]`` - - ``join(``, @)`` - - "ab" - * - ``["a", false, "b"]`` - - ``join(`, `, @)`` - - ```` - * - ``[false]`` - - ``join(`, `, @)`` - - ```` - - -keys ----- - -:: - - array keys(object $obj) - -Returns an array containing the keys of the provided object. - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``{"foo": "baz", "bar": "bam"}`` - - ``keys(@)`` - - ``["foo", "bar"]`` - * - ``{}`` - - ``keys(@)`` - - ``[]`` - * - ``false`` - - ``keys(@)`` - - ```` - * - ``[b, a, c]`` - - ``keys(@)`` - - ```` - - -length ------- - -:: - - number length(string|array|object $subject) - -Returns the length of the given argument using the following types rules: - -1. string: returns the number of code points in the string -2. array: returns the number of elements in the array -3. object: returns the number of key-value pairs in the object - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - n/a - - ``length(`abc`)`` - - 3 - * - "current" - - ``length(@)`` - - 7 - * - "current" - - ``length(not_there)`` - - ```` - * - ``["a", "b", "c"]`` - - ``length(@)`` - - 3 - * - ``[]`` - - ``length(@)`` - - 0 - * - ``{}`` - - ``length(@)`` - - 0 - * - ``{"foo": "bar", "baz": "bam"}`` - - ``length(@)`` - - 2 - - -max ---- - -:: - - number max(array[number] $collection) - -Returns the highest found number in the provided array argument. - -An empty array will produce a return value of null. - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``[10, 15]`` - - ``max(@)`` - - 15 - * - ``[10, false, 20]`` - - ``max(@)`` - - ```` - - -min ---- - -:: - - number min(array[number] $collection) - -Returns the lowest found number in the provided ``$collection`` argument. - - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``[10, 15]`` - - ``min(@)`` - - 10 - * - ``[10, false, 20]`` - - ``min(@)`` - - ```` - - -sort ----- - -:: - - array sort(array $list) - -This function accepts an array ``$list`` argument and returns the sorted -elements of the ``$list`` as an array. - -The array must be a list of strings or numbers. Sorting strings is based on -code points. Locale is not taken into account. - - - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``[b, a, c]`` - - ``sort(@)`` - - ``[a, b, c]`` - * - ``[1, a, c]`` - - ``sort(@)`` - - ``[1, a, c]`` - * - ``[false, [], null]`` - - ``sort(@)`` - - ``[[], null, false]`` - * - ``[[], {}, false]`` - - ``sort(@)`` - - ``[{}, [], false]`` - * - ``{"a": 1, "b": 2}`` - - ``sort(@)`` - - ``null`` - * - ``false`` - - ``sort(@)`` - - ``null`` - - -to_string ---------- - -:: - - string to_string(string|number|array|object|boolean $arg) - -* string - Returns the passed in value. -* number/array/object/boolean - The JSON encoded value of the object. The - JSON encoder should emit the encoded JSON value without adding any additional - new lines. - - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``null`` - - ``to_string(`2`)`` - - ``"2"`` - - -to_number ---------- - -:: - - number to_number(string|number $arg) - -* string - Returns the parsed number. Any string that conforms to the - ``json-number`` production is supported. -* number - Returns the passed in value. -* array - null -* object - null -* boolean - null - - -type ----- - -:: - - string type(array|object|string|number|boolean|null $subject) - -Returns the JavaScript type of the given ``$subject`` argument as a string -value. - -The return value MUST be one of the following: - -* number -* string -* boolean -* array -* object -* null - - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - "foo" - - ``type(@)`` - - "string" - * - ``true`` - - ``type(@)`` - - "boolean" - * - ``false`` - - ``type(@)`` - - "boolean" - * - ``null`` - - ``type(@)`` - - "null" - * - 123 - - ``type(@)`` - - number - * - 123.05 - - ``type(@)`` - - number - * - ``["abc"]`` - - ``type(@)`` - - "array" - * - ``{"abc": "123"}`` - - ``type(@)`` - - "object" - - -values ------- - -:: - - array values(object $obj) - -Returns the values of the provided object. - - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``{"foo": "baz", "bar": "bam"}`` - - ``values(@)`` - - ``["baz", "bam"]`` - * - ``["a", "b"]`` - - ``values(@)`` - - ```` - * - ``false`` - - ``values(@)`` - - ```` - - -Compliance Tests -================ - -A ``functions.json`` will be added to the compliance test suite. -The test suite will add the following new error types: - -* unknown-function -* invalid-arity -* invalid-type - -The compliance does not specify **when** the errors are raised, as this will -depend on implementation details. For an implementation to be compliant they -need to indicate that an error occurred while attempting to evaluate the -JMESPath expression. - -History -======= - -* This JEP originally proposed the literal syntax. The literal portion of this - JEP was removed and added instead to JEP 7. -* This JEP originally specified that types matches should return null. This - has been updated to specify that an invalid type error should occur instead. diff --git a/docs/proposals/improved-identifiers.rst b/docs/proposals/improved-identifiers.rst deleted file mode 100644 index e8633272..00000000 --- a/docs/proposals/improved-identifiers.rst +++ /dev/null @@ -1,234 +0,0 @@ -==================== -Improved Identifiers -==================== - -:JEP: 6 -:Author: James Saryerwinnie -:Status: draft -:Created: 14-Dec-2013 -:Last Updated: 15-Dec-2013 - - -Abstract -======== - -This JEP proposes grammar modifications to JMESPath in order to improve -identifiers used in JMESPath. In doing so, several inconsistencies in the -identifier grammar rules will be fixed, along with an improved grammar for -specifying unicode identifiers in a way that is consistent with JSON -strings. - - -Motivation -========== - -There are two ways to currently specify an identifier, the unquoted rule:: - - identifier = 1*char - -and the quoted rule:: - - identifier =/ quote 1*(unescaped-char / escaped-quote) quote - -The ``char`` rule contains a set of characters that do **not** have to be -quoted:: - - char = %x30-39 / ; 0-9 - %x41-5A / ; A-Z - %x5F / ; _ - %x61-7A / ; a-z - %x7F-10FFFF - -There is an ambiguity between the ``%x30-39`` rule and the ``number`` rule:: - - number = ["-"]1*digit - digit = "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" / "0" - -It's ambiguous which rule to use. Given a string "123", it's not clear whether -this should be parsed as an identifier or a number. Existing implementations -**aren't** following this rule (because it's ambiguous) so the grammar should -be updated to remove the ambiguity, specifically, an unquoted identifier can -only start with the characters ``[a-zA-Z_]``. - -Unicode -------- - -JMESPath supports unicode through the ``char`` and ``unescaped-char`` rule:: - - unescaped-char = %x30-10FFFF - char = %x30-39 / ; 0-9 - %x41-5A / ; A-Z - %x5F / ; _ - %x61-7A / ; a-z - %x7F-10FFFF - -However, JSON supports a syntax for escaping unicode characters. Any -character in the Basic Multilingual Plane (BMP) can be escaped with:: - - char = escape (%x75 4HEXDIG ) ; \uXXXX - -Similar to the way that XPath supports numeric character references used -in XML (``&#nnnn``), JMESPath should support the same escape sequences -used in JSON. JSON also supports a 12 character escape sequence for -characters outside of the BMP, by encoding the UTF-16 surrogate pair. -For example, the code point ``U+1D11E`` can be represented -as ``"\uD834\uDD1E"``. - - -Escape Sequences ----------------- - -Consider the following JSON object:: - - {"foo\nbar": "baz"} - -A JMESPath expression should be able to retrieve the value of baz. With -the current grammar, one must rely on the environment's ability to input -control characters such as the newline (``%x0A``). This can be problematic -in certain environments. For example, in python, this is not a problem:: - - >>> jmespath_expression = "foo\nbar" - -Python will interpret the sequence ``"\n"`` (``%x5C %x6E``) as the newline -character ``%x0A``. However, consider Bash:: - - $ foo --jmespath-expression "foo\nbar" - -In this situation, bash will not interpret the ``"\n"`` (``%x5C %x6E``) sequence. - - -Specification -============= - -The ``char`` rule contains a set of characters that do **not** have to be -quoted. The new set of characters that do not have to quoted will be:: - - unquoted-string = (%x41-5A / %x61-7A / %x5F) *(%x30-39 / %x41-5A / %x5F / %x61-7A) - -In order for an identifier to not be quoted, it must start with ``[A-Za-z_]``, -then must be followed by zero or more ``[0-9A-Za-z_]``. - -The unquoted rule is updated to account for all JSON supported escape -sequences:: - - quoted-string =/ quote 1*(unescaped-char / escaped-char) quote - -The full rule for an identifier is:: - - identifier = unquoted-string / quoted-string - unquoted-string = (%x41-5A / %x61-7A / %x5F) *( ; a-zA-Z_ - %x30-39 / ; 0-9 - %x41-5A / ; A-Z - %x5F / ; _ - %x61-7A) ; a-z - quoted-string = quote 1*(unescaped-char / escaped-char) quote - unescaped-char = %x20-21 / %x23-5B / %x5D-10FFFF - escape = %x5C ; Back slash: \ - quote = %x22 ; Double quote: '"' - escaped-char = escape ( - %x22 / ; " quotation mark U+0022 - %x5C / ; \ reverse solidus U+005C - %x2F / ; / solidus U+002F - %x62 / ; b backspace U+0008 - %x66 / ; f form feed U+000C - %x6E / ; n line feed U+000A - %x72 / ; r carriage return U+000D - %x74 / ; t tab U+0009 - %x75 4HEXDIG ) ; uXXXX U+XXXX - - -Rationale -========= - -Adopting the same string rules as JSON strings will allow users familiar with -JSON semantics to understand how JMESPath identifiers will work. - -This change also provides a nice consistency for the literal syntax proposed -in JEP 3. With this model, the supported literal strings can be the same -as quoted identifiers. - -This also will allow the grammar to grow in a consistent way if JMESPath -adds support for filtering based on literal values. For example (note that -this is just a suggested syntax, not a formal proposal), given the data:: - - {"foo": [{"✓": "✓"}, {"✓": "✗"}]} - -You can now have the following JMESPath expressions:: - - foo[?"✓" = `✓`] - foo[?"\u2713" = `\u2713`] - -As a general property, any supported JSON string is now a supported quoted -identifier. - - -Impact -====== - -For any implementation that was parsing digits as an identifier, identifiers -starting with digits will no longer be valid, e.g. ``foo.0.1.2``. - -There are several compliance tests that will have to be updated as a result -of this JEP. They were arguably wrong to begin with. - -basic.json ----------- - -The following needs to be changed because identifiers starting -with a number must now be quoted:: - - - "expression": "foo.1", - + "expression": "foo.\"1\"", - "result": ["one", "two", "three"] - }, - { - - "expression": "foo.1[0]", - + "expression": "foo.\"1\"[0]", - "result": "one" - }, - -Similarly, the following needs to be changed because an unquoted -identifier cannot start with ``-``:: - - - "expression": "foo.-1", - + "expression": "foo.\"-1\"", - "result": "bar" - } - - -escape.json ------------ - -The escape.json has several more interesting cases that need to be updated. -This has to do with the updated escaping rules. Each one will be explained. - -:: - - - "expression": "\"foo\nbar\"", - + "expression": "\"foo\\nbar\"", - "result": "newline" - }, - - -This has to be updated because a JSON parser will interpret the ``\n`` sequence -as the newline character. The newline character is **not** allowed in a -JMESPath identifier (note that the newline character ``%0A`` is not in any -rule). In order for a JSON parser to create a sequence of ``%x5C %x6E``, the -JSON string must be ``\\n`` (``%x5C %x5C %x6E``). - -:: - - - "expression": "\"c:\\\\windows\\path\"", - + "expression": "\"c:\\\\\\\\windows\\\\path\"", - "result": "windows" - }, - - -The above example is a more pathological case of escaping. In this example, we -have a string that represents a windows path "c:\\windowpath". There are two -levels of escaping happening here, one at the JSON parser, and one at the -JMESPath parser. The JSON parser will take the sequence -``"\"c:\\\\\\\\windows\\\\path\""`` and create the string -``"\"c:\\\\windows\\path\""``. The JMESPath parser will take the string -``"\"c:\\\\windows\\path\"'`` and, applying its own escaping rules, will -look for a key named ``c:\\windows\path``. diff --git a/docs/proposals/nested-expressions.rst b/docs/proposals/nested-expressions.rst deleted file mode 100644 index 97028fbe..00000000 --- a/docs/proposals/nested-expressions.rst +++ /dev/null @@ -1,221 +0,0 @@ -================== -Nested Expressions -================== - -:JEP: 1 -:Author: Michael Dowling -:Status: accepted -:Created: 27-Nov-2013 - -Abstract -======== - -This document proposes modifying the `JMESPath grammar `_ -to support arbitrarily nested expressions within ``multi-select-list`` and -``multi-select-hash`` expressions. - -Motivation -========== - -This JMESPath grammar currently does not allow arbitrarily nested expressions -within ``multi-select-list`` and ``multi-select-hash`` expressions. This -prevents nested branching expressions, nested ``multi-select-list`` expressions -within other multi expressions, and nested ``or-expression``s within any -multi-expression. - -By allowing any expression to be nested within a ``multi-select-list`` and -``multi-select-hash`` expression, we can trim down several grammar rules and -provide customers with a much more flexible expression DSL. - -Supporting arbitrarily nested expressions within other expressions requires: - -* Updating the grammar to remove ``non-branched-expr`` -* Updating compliance tests to add various permutations of the grammar to - ensure implementations are compliant. -* Updating the JMESPath documentation to reflect the ability to arbitrarily - nest expressions. - -Nested Expression Examples -========================== - -Nested branch expressions -------------------------- - -Given: - -.. code-block:: json - - { - "foo": { - "baz": [ - { - "bar": "abc" - }, { - "bar": "def" - } - ], - "qux": ["zero"] - } - } - -With: ``foo.[baz[*].bar, qux[0]]`` - -Result: - -.. code-block:: json - - [ - [ - "abc", - "def" - ], - "zero" - ] - -Nested branch expressions with nested mutli-select --------------------------------------------------- - -Given: - -.. code-block:: json - - { - "foo": { - "baz": [ - { - "bar": "a", - "bam": "b", - "boo": "c" - }, { - "bar": "d", - "bam": "e", - "boo": "f" - } - ], - "qux": ["zero"] - } - } - -With: ``foo.[baz[*].[bar, boo], qux[0]]`` - -Result: - -.. code-block:: json - - [ - [ - [ - "a", - "c" - ], - [ - "d", - "f" - ] - ], - "zero" - ] - -Nested or expressions ---------------------- - -Given: - -.. code-block:: json - - { - "foo": { - "baz": [ - { - "bar": "a", - "bam": "b", - "boo": "c" - }, { - "bar": "d", - "bam": "e", - "boo": "f" - } - ], - "qux": ["zero"] - } - } - -With: ``foo.[baz[*].not_there || baz[*].bar, qux[0]]`` - -Result: - -.. code-block:: json - - [ - [ - "a", - "d" - ], - "zero" - ] - -No breaking changes -------------------- - -Because there are no breaking changes from this modification, existing -multi-select expressions will still work unchanged: - -Given: - -.. code-block:: json - - { - "foo": { - "baz": { - "abc": 123, - "bar": 456 - } - } - } - -With: ``foo.[baz, baz.bar]`` - -Result: - -.. code-block:: json - - [ - { - "abc": 123, - "bar": 456 - }, - 456 - ] - -Modified Grammar -================ - -The following modified JMESPath grammar supports arbitrarily nested expressions -and is specified using ABNF, as described in `RFC4234`_ - -:: - - expression = sub-expression / index-expression / or-expression / identifier / "*" - expression =/ multi-select-list / multi-select-hash - sub-expression = expression "." expression - or-expression = expression "||" expression - index-expression = expression bracket-specifier / bracket-specifier - multi-select-list = "[" ( expression *( "," expression ) ) "]" - multi-select-hash = "{" ( keyval-expr *( "," keyval-expr ) ) "}" - keyval-expr = identifier ":" expression - bracket-specifier = "[" (number / "*") "]" - number = [-]1*digit - digit = "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" / "0" - identifier = 1*char - identifier =/ quote 1*(unescaped-char / escaped-quote) quote - escaped-quote = escape quote - unescaped-char = %x30-10FFFF - escape = %x5C ; Back slash: \ - quote = %x22 ; Double quote: '"' - char = %x30-39 / ; 0-9 - %x41-5A / ; A-Z - %x5F / ; _ - %x61-7A / ; a-z - %x7F-10FFFF - -.. _RFC4234: http://tools.ietf.org/html/rfc4234 diff --git a/docs/proposals/pipes.rst b/docs/proposals/pipes.rst deleted file mode 100644 index 965b3574..00000000 --- a/docs/proposals/pipes.rst +++ /dev/null @@ -1,200 +0,0 @@ -================ -Pipe Expressions -================ - -:JEP: 4 -:Author: Michael Dowling -:Status: accepted -:Created: 07-Dec-2013 - -Abstract -======== - -This document proposes adding support for piping expressions into subsequent -expressions. - -Motivation -========== - -The current JMESPath grammar allows for projections at various points in an -expression. However, it is not currently possible to operate on the result of -a projection as a list. - -The following example illustrates that it is not possible to operate on the -result of a projection (e.g., take the first match of a projection). - -Given: - -.. code-block:: json - - { - "foo": { - "a": { - "bar": [1, 2, 3] - }, - "b": { - "bar": [4, 5, 6] - } - } - } - -Expression: - -:: - - foo.*.bar[0] - -The result would be element 0 of each ``bar``: - -.. code-block:: json - - [1, 4] - -With the addition of filters, we could pass the result of one expression to -another, operating on the result of a projection (or any expression). - -Expression: - -:: - - foo.*.bar | [0] - -Result: - -.. code-block:: json - - [1, 2, 3] - -Not only does this give us the ability to operate on the result of a -projection, but pipe expressions can also be useful for breaking down a complex -expression into smaller, easier to comprehend, parts. - -Modified Grammar -================ - -The following modified JMESPath grammar supports piped expressions. - -:: - - expression = sub-expression / index-expression / or-expression / identifier / "*" - expression =/ multi-select-list / multi-select-hash / pipe-expression - sub-expression = expression "." expression - pipe-expression = expression "|" expression - or-expression = expression "||" expression - index-expression = expression bracket-specifier / bracket-specifier - multi-select-list = "[" ( expression *( "," expression ) ) "]" - multi-select-hash = "{" ( keyval-expr *( "," keyval-expr ) ) "}" - keyval-expr = identifier ":" expression - bracket-specifier = "[" (number / "*") "]" / "[]" - number = [-]1*digit - digit = "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" / "0" - identifier = 1*char - identifier =/ quote 1*(unescaped-char / escaped-quote) quote - escaped-quote = escape quote - unescaped-char = %x30-10FFFF - escape = %x5C ; Back slash: \ - quote = %x22 ; Double quote: '"' - char = %x30-39 / ; 0-9 - %x41-5A / ; A-Z - %x5F / ; _ - %x61-7A / ; a-z - %x7F-10FFFF - -.. _RFC4234: http://tools.ietf.org/html/rfc4234 - -.. note:: - - ``pipe-expression`` has a higher precedent than the ``or-operator`` - -Compliance Tests -================ - -.. code-block:: json - - [{ - "given": { - "foo": { - "bar": { - "baz": "one" - }, - "other": { - "baz": "two" - }, - "other2": { - "baz": "three" - }, - "other3": { - "notbaz": ["a", "b", "c"] - }, - "other4": { - "notbaz": ["d", "e", "f"] - } - } - }, - "cases": [ - { - "expression": "foo.*.baz | [0]", - "result": "one" - }, - { - "expression": "foo.*.baz | [1]", - "result": "two" - }, - { - "expression": "foo.*.baz | [2]", - "result": "three" - }, - { - "expression": "foo.bar.* | [0]", - "result": "one" - }, - { - "expression": "foo.*.notbaz | [*]", - "result": [["a", "b", "c"], ["d", "e", "f"]] - }, - { - "expression": "foo | bar", - "result": {"baz": "one"} - }, - { - "expression": "foo | bar | baz", - "result": "one" - }, - { - "expression": "foo|bar| baz", - "result": "one" - }, - { - "expression": "not_there | [0]", - "result": null - }, - { - "expression": "not_there | [0]", - "result": null - }, - { - "expression": "[foo.bar, foo.other] | [0]", - "result": {"baz": "one"} - }, - { - "expression": "{\"a\": foo.bar, \"b\": foo.other} | a", - "result": {"baz": "one"} - }, - { - "expression": "{\"a\": foo.bar, \"b\": foo.other} | b", - "result": {"baz": "two"} - }, - { - "expression": "{\"a\": foo.bar, \"b\": foo.other} | *.baz", - "result": ["one", "two"] - }, - { - "expression": "foo.bam || foo.bar | baz", - "result": "one" - }, - { - "expression": "foo | not_there || bar", - "result": {"baz": "one"} - } - ] - }] diff --git a/docs/specification.rst b/docs/specification.rst deleted file mode 100644 index 854fe546..00000000 --- a/docs/specification.rst +++ /dev/null @@ -1,1615 +0,0 @@ -====================== -JMESPath Specification -====================== - -.. warning:: - - This page is deprecated and will be removed in the near future. - Go to http://jmespath.org/specification.html for the latest - JMESPath specification. - - -This document describes the specification for jmespath. -In the specification, examples are shown through the use -of a ``search`` function. The syntax for this function is:: - - search(, ) -> - -For simplicity, the jmespath expression and the JSON document are -not quoted. For example:: - - search(foo, {"foo": "bar"}) -> "bar" - -In this specification, ``null`` is used as a return value whenever an -expression does not match. ``null`` is the generic term that maps to the JSON -``null`` value. Implementations can replace the ``null`` value with the -language equivalent value. - - -Grammar -======= - -The grammar is specified using ABNF, as described in `RFC4234`_ - -:: - - expression = sub-expression / index-expression / or-expression / identifier - expression =/ "*" / multi-select-list / multi-select-hash / literal - expression =/ function-expression / pipe-expression - sub-expression = expression "." ( identifier / - multi-select-list / - multi-select-hash / - function-expression / - "*" ) - or-expression = expression "||" expression - pipe-expression = expression "|" expression - index-expression = expression bracket-specifier / bracket-specifier - multi-select-list = "[" ( expression *( "," expression ) ) "]" - multi-select-hash = "{" ( keyval-expr *( "," keyval-expr ) ) "}" - keyval-expr = identifier ":" expression - bracket-specifier = "[" (number / "*" / slice-expression) "]" / "[]" - bracket-specifier =/ "[?" list-filter-expr "]" - list-filter-expr = expression comparator expression - slice-expression = [number] ":" [number] [ ":" [number] ] - comparator = "<" / "<=" / "==" / ">=" / ">" / "!=" - function-expression = unquoted-string ( - no-args / - one-or-more-args ) - no-args = "(" ")" - one-or-more-args = "(" ( function-arg *( "," function-arg ) ) ")" - function-arg = expression / current-node / expression-type - current-node = "@" - expression-type = "&" expression - - literal = "`" json-value "`" - literal =/ "`" 1*(unescaped-literal / escaped-literal) "`" - unescaped-literal = %x20-21 / ; space ! - %x23-5A / ; # - [ - %x5D-5F / ; ] ^ _ - %x61-7A ; a-z - %x7C-10FFFF ; |}~ ... - escaped-literal = escaped-char / (escape %x60) - number = ["-"]1*digit - digit = %x30-39 - identifier = unquoted-string / quoted-string - unquoted-string = (%x41-5A / %x61-7A / %x5F) *( ; a-zA-Z_ - %x30-39 / ; 0-9 - %x41-5A / ; A-Z - %x5F / ; _ - %x61-7A) ; a-z - quoted-string = quote 1*(unescaped-char / escaped-char) quote - unescaped-char = %x20-21 / %x23-5B / %x5D-10FFFF - escape = %x5C ; Back slash: \ - quote = %x22 ; Double quote: '"' - escaped-char = escape ( - %x22 / ; " quotation mark U+0022 - %x5C / ; \ reverse solidus U+005C - %x2F / ; / solidus U+002F - %x62 / ; b backspace U+0008 - %x66 / ; f form feed U+000C - %x6E / ; n line feed U+000A - %x72 / ; r carriage return U+000D - %x74 / ; t tab U+0009 - %x75 4HEXDIG ) ; uXXXX U+XXXX - - ; The ``json-value`` is any valid JSON value with the one exception that the - ; ``%x60`` character must be escaped. While it's encouraged that implementations - ; use any existing JSON parser for this grammar rule (after handling the escaped - ; literal characters), the grammar rule is shown below for completeness:: - - json-value = false / null / true / json-object / json-array / - json-number / json-quoted-string - false = %x66.61.6c.73.65 ; false - null = %x6e.75.6c.6c ; null - true = %x74.72.75.65 ; true - json-quoted-string = %x22 1*(unescaped-literal / escaped-literal) %x22 - begin-array = ws %x5B ws ; [ left square bracket - begin-object = ws %x7B ws ; { left curly bracket - end-array = ws %x5D ws ; ] right square bracket - end-object = ws %x7D ws ; } right curly bracket - name-separator = ws %x3A ws ; : colon - value-separator = ws %x2C ws ; , comma - ws = *(%x20 / ; Space - %x09 / ; Horizontal tab - %x0A / ; Line feed or New line - %x0D ; Carriage return - ) - json-object = begin-object [ member *( value-separator member ) ] end-object - member = quoted-string name-separator json-value - json-array = begin-array [ json-value *( value-separator json-value ) ] end-array - json-number = [ minus ] int [ frac ] [ exp ] - decimal-point = %x2E ; . - digit1-9 = %x31-39 ; 1-9 - e = %x65 / %x45 ; e E - exp = e [ minus / plus ] 1*DIGIT - frac = decimal-point 1*DIGIT - int = zero / ( digit1-9 *DIGIT ) - minus = %x2D ; - - plus = %x2B ; + - zero = %x30 ; 0 - - -Identifiers -=========== - - -:: - - identifier = unquoted-string / quoted-string - unquoted-string = (%x41-5A / %x61-7A / %x5F) *( ; a-zA-Z_ - %x30-39 / ; 0-9 - %x41-5A / ; A-Z - %x5F / ; _ - %x61-7A) ; a-z - quoted-string = quote 1*(unescaped-char / escaped-char) quote - unescaped-char = %x20-21 / %x23-5B / %x5D-10FFFF - escape = %x5C ; Back slash: \ - quote = %x22 ; Double quote: '"' - escaped-char = escape ( - %x22 / ; " quotation mark U+0022 - %x5C / ; \ reverse solidus U+005C - %x2F / ; / solidus U+002F - %x62 / ; b backspace U+0008 - %x66 / ; f form feed U+000C - %x6E / ; n line feed U+000A - %x72 / ; r carriage return U+000D - %x74 / ; t tab U+0009 - %x75 4HEXDIG ) ; uXXXX U+XXXX - -An ``identifier`` is the most basic expression and can be used to extract a single -element from a JSON document. The return value for an ``identifier`` is the -value associated with the identifier. If the ``identifier`` does not exist in -the JSON document, than a ``null`` value is returned. - -From the grammar rule listed above identifiers can be one of more characters, -and must start with ``A-Za-z_``. - -An identifier can also be quoted. This is necessary when an identifier has -characters not specified in the ``unquoted-string`` grammar rule. -In this situation, an identifier is specified with a double quote, followed by -any number of ``unescaped-char`` or ``escaped-char`` characters, followed by a -double quote. The ``quoted-string`` rule is the same grammar rule as a JSON -string, so any valid string can be used between double quoted, include JSON -supported escape sequences, and six character unicode escape sequences. - -Note that any identifier that does not start with ``A-Za-z_`` **must** -be quoted. - - -Examples --------- - -:: - - search(foo, {"foo": "value"}) -> "value" - search(bar, {"foo": "value"}) -> null - search(foo, {"foo": [0, 1, 2]}) -> [0, 1, 2] - search("with space", {"with space": "value"}) -> "value" - search("special chars: !@#", {"special chars: !@#": "value"}) -> "value" - search("quote\"char", {"quote\"char": "value"}) -> "value" - search("\u2713", {"\u2713": "value"}) -> "value" - - -SubExpressions -============== - -:: - - sub-expression = expression "." ( identifier / - multi-select-list / - multi-select-hash / - function-expression / - "*" ) - -A subexpression is a combination of two expressions separated by the '.' char. -A subexpression is evaluated as follows: - -* Evaluate the expression on the left with the original JSON document. -* Evaluate the expression on the right with the result of the left expression - evaluation. - -In pseudocode:: - - left-evaluation = search(left-expression, original-json-document) - result = search(right-expression, left-evaluation) - - -A subexpression is itself an expression, so there can be multiple levels of -subexpressions: ``grandparent.parent.child``. - - -Examples --------- - -Given a JSON document: ``{"foo": {"bar": "baz"}}``, and a jmespath expression: -``foo.bar``, the evaluation process would be:: - - left-evaluation = search("foo", {"foo": {"bar": "baz"}}) -> {"bar": "baz"} - result = search("bar": {"bar": "baz"}) -> "baz" - -The final result in this example is ``"baz"``. - -Additional examples:: - - search(foo.bar, {"foo": {"bar": "value"}}) -> "value" - search(foo.bar, {"foo": {"baz": "value"}}) -> null - search(foo.bar.baz, {"foo": {"bar": {"baz": "value"}}}) -> "value" - - -Index Expressions -================= - -:: - - index-expression = expression bracket-specifier / bracket-specifier - bracket-specifier = "[" (number / "*" / slice-expression) "]" / "[]" - slice-expression = [number] ":" [number] [ ":" [number] ] - -An index expression is used to access elements in a list. Indexing is 0 based, -the index of 0 refers to the first element of the list. A negative number is a -valid index. A negative number indicates that indexing is relative to the end -of the list, specifically:: - - negative-index == (length of array) + negative-index - -Given an array of length ``N``, an index of ``-1`` would be equal to a positive -index of ``N - 1``, which is the last element of the list. If an index -expression refers to an index that is greater than the length of the array, a -value of ``null`` is returned. - -For the grammar rule ``expression bracket-specifier`` the ``expression`` is -first evaluated, and then return value from the ``expression`` is given as -input to the ``bracket-specifier``. - -Using a "*" character within a ``bracket-specifier`` is discussed below in the -``wildcard expressions`` section. - -Slices ------- - -:: - - slice-expression = [number] ":" [number] [ ":" [number] ] - -A slice expression allows you to select a contiguous subset of an array. A -slice has a ``start``, ``stop``, and ``step`` value. The general form of a -slice is ``[start:stop:step]``, but each component is optional and can -be omitted. - -.. note:: - - Slices in JMESPath have the same semantics as python slices. - -Given a ``start``, ``stop``, and ``step`` value, the sub elements in an array -are extracted as follows: - -* The first element in the extracted array is the index denoted by ``start``. -* The last element in the extracted array is the index denoted by ``end - 1``. -* The ``step`` value determines how many indices to skip after each element - is selected from the array. An array of 1 (the default step) will not skip - any indices. A step value of 2 will skip every other index while extracting - elements from an array. A step value of -1 will extract values in reverse - order from the array. - - -Slice expressions adhere to the following rules: - -* If a negative start position is given, it is calculated as the total length - of the array plus the given start position. -* If no start position is given, it is assumed to be 0 if the given step is - greater than 0 or the end of the array if the given step is less than 0. -* If a negative stop position is given, it is calculated as the total length - of the array plus the given stop position. -* If no stop position is given, it is assumed to be the length of the array if - the given step is greater than 0 or 0 if the given step is less than 0. -* If the given step is omitted, it it assumed to be 1. -* If the given step is 0, an error MUST be raised. -* If the element being sliced is not an array, the result is ``null``. -* If the element being sliced is an array and yields no results, the result - MUST be an empty array. - - -Examples --------- - -:: - - search([0:4:1], [0, 1, 2, 3]) -> [0, 1, 2, 3] - search([0:4], [0, 1, 2, 3]) -> [0, 1, 2, 3] - search([0:3], [0, 1, 2, 3]) -> [0, 1, 2] - search([:2], [0, 1, 2, 3]) -> [0, 1] - search([::2], [0, 1, 2, 3]) -> [0, 2] - search([::-1], [0, 1, 2, 3]) -> [3, 2, 1, 0] - search([-2:], [0, 1, 2, 3]) -> [2, 3] - - -Flatten Operator ----------------- - -When the character sequence ``[]`` is provided as a bracket specifier, then -a flattening operation occurs on the current result. The flattening operator -will merge sublists in the current result into a single list. The flattening -operator has the following semantics: - -* Create an empty result list. -* Iterate over the elements of the current result. -* If the current element is not a list, add to the end of the result list. -* If the current element is a list, add each element of the current element - to the end of the result list. -* The result list is now the new current result. - -Once the flattening operation has been performed, subsequent operations -are projected onto the flattened list with the same semantics as a -wildcard expression. Thus the difference between ``[*]`` and ``[]`` is that -``[]`` will first flatten sublists in the current result. - - -Examples --------- - -:: - - search([0], ["first", "second", "third"]) -> "first" - search([-1], ["first", "second", "third"]) -> "third" - search([100], ["first", "second", "third"]) -> null - search(foo[0], {"foo": ["first", "second", "third"]) -> "first" - search(foo[100], {"foo": ["first", "second", "third"]) -> null - search(foo[0][0], {"foo": [[0, 1], [1, 2]]}) -> 0 - - -Or Expressions -============== - -:: - - or-expression = expression "||" expression - -An or expression will evaluate to either the left expression or the right -expression. If the evaluation of the left expression is not false it is used as -the return value. If the evaluation of the right expression is not false it is -used as the return value. If neither the left or right expression are -non-null, then a value of null is returned. A false value corresponds to any -of the following conditions:: - -* Empty list: ``[]`` -* Empty object: ``{}`` -* Empty string: ``""`` -* False boolean: ``false`` -* Null value: ``null`` - -A true value corresponds to any value that is not false. - - -Examples --------- - -:: - - search(foo || bar, {"foo": "foo-value"}) -> "foo-value" - search(foo || bar, {"bar": "bar-value"}) -> "bar-value" - search(foo || bar, {"foo": "foo-value", "bar": "bar-value"}) -> "foo-value" - search(foo || bar, {"baz": "baz-value"}) -> null - search(foo || bar || baz, {"baz": "baz-value"}) -> "baz-value" - search(override || mylist[-1], {"mylist": ["one", "two"]}) -> "two" - search(override || mylist[-1], {"mylist": ["one", "two"], "override": "yes"}) -> "yes" - - -MultiSelect List -================ - -:: - - multi-select-list = "[" ( expression *( "," expression ) "]" - -A multiselect expression is used to extract a subset of elements from a JSON -hash. There are two version of multiselect, one in which the multiselect -expression is enclosed in ``{...}`` and one which is enclosed in ``[...]``. -This section describes the ``[...]`` version. Within the start and closing -characters is one or more non expressions separated by a comma. Each -expression will be evaluated against the JSON document. Each returned element -will be the result of evaluating the expression. A ``multi-select-list`` with -``N`` expressions will result in a list of length ``N``. Given a multiselect -expression ``[expr-1,expr-2,...,expr-n]``, the evaluated expression will return -``[evaluate(expr-1), evaluate(expr-2), ..., evaluate(expr-n)]``. - -Examples --------- - -:: - - search([foo,bar], {"foo": "a", "bar": "b", "baz": "c"}) -> ["a", "b"] - search([foo,bar[0]], {"foo": "a", "bar": ["b"], "baz": "c"}) -> ["a", "b"] - search([foo,bar.baz], {"foo": "a", "bar": {"baz": "b"}}) -> ["a", "b"] - search([foo,baz], {"foo": "a", "bar": "b"}) -> ["a", null] - - -MultiSelect Hash -================ - -:: - - multi-select-hash = "{" ( keyval-expr *( "," keyval-expr ) "}" - keyval-expr = identifier ":" expression - -A ``multi-select-hash`` expression is similar to a ``multi-select-list`` -expression, except that a hash is created instead of a list. A -``multi-select-hash`` expression also requires key names to be provided, as -specified in the ``keyval-expr`` rule. Given the following rule:: - - keyval-expr = identifier ":" expression - -The ``identifier`` is used as the key name and the result of evaluating the -``expression`` is the value associated with the ``identifier`` key. - -Each ``keyval-expr`` within the ``multi-select-hash`` will correspond to a -single key value pair in the created hash. - - -Examples --------- - -Given a ``multi-select-hash`` expression ``{foo: one.two, bar: bar}`` and the -data ``{"bar": "bar", {"one": {"two": "one-two"}}}``, the expression is -evaluated as follows: - -1. A hash is created: ``{}`` -2. A key ``foo`` is created whose value is the result of evaluating ``one.two`` - against the provided JSON document: ``{"foo": evaluate(one.two, )}`` -3. A key ``bar`` is created whose value is the result of evaluating the - expression ``bar`` against the provided JSON document. - -The final result will be: ``{"foo": "one-two", "bar": "bar"}``. - -Additional examples: - -:: - - search({foo: foo, bar: bar}, {"foo": "a", "bar": "b", "baz": "c"}) - -> {"foo": "a", "bar": "b"} - search({foo: foo, firstbar: bar[0]}, {"foo": "a", "bar": ["b"]}) - -> {"foo": "a", "firstbar": "b"} - search({foo: foo, "bar.baz": bar.baz}, {"foo": "a", "bar": {"baz": "b"}}) - -> {"foo": "a", "bar.baz": "b"} - search({foo: foo, baz: baz}, {"foo": "a", "bar": "b"}) - -> {"foo": "a", "bar": null} - - -Wildcard Expressions -==================== - -:: - - expression =/ "*" - bracket-specifier = "[" "*" "]" - -A wildcard expression is a expression of either ``*`` or ``[*]``. A wildcard -expression can return multiple elements, and the remaining expressions are -evaluated against each returned element from a wildcard expression. The -``[*]`` syntax applies to a list type and the ``*`` syntax applies to a hash -type. - -The ``[*]`` syntax (referred to as a list wildcard expression) will return all -the elements in a list. Any subsequent expressions will be evaluated against -each individual element. Given an expression ``[*].child-expr``, and a list of -N elements, the evaluation of this expression would be ``[child-expr(el-0), -child-expr(el-2), ..., child-expr(el-N)]``. This is referred to as a -**projection**, and the ``child-expr`` expression is projected onto the -elements of the resulting list. - -Once a projection has been created, all subsequent expressions are projected -onto the resulting list. - -The ``*`` syntax (referred to as a hash wildcard expression) will return a list -of the hash element's values. Any subsequent expression will be evaluated -against each individual element in the list (this is also referred to as a -**projection**). - -Note that if any subsequent expression after a wildcard expression returns a -``null`` value, it is omitted from the final result list. - -A list wildcard expression is only valid for the JSON array type. If a list -wildcard expression is applied to any other JSON type, a value of ``null`` is -returned. - -Similarly, a hash wildcard expression is only valid for the JSON object type. -If a hash wildcard expression is applied to any other JSON type, a value of -``null`` is returned. - -Examples --------- - -:: - - search([*].foo, [{"foo": 1}, {"foo": 2}, {"foo": 3}]) -> [1, 2, 3] - search([*].foo, [{"foo": 1}, {"foo": 2}, {"bar": 3}]) -> [1, 2] - search('*.foo', {"a": {"foo": 1}, "b": {"foo": 2}, "c": {"bar": 1}}) -> [1, 2] - - -Literal Expressions -=================== - -:: - - literal = "`" json-value "`" - literal =/ "`" 1*(unescaped-literal / escaped-literal) "`" - unescaped-literal = %x20-21 / ; space ! - %x23-5A / ; # - [ - %x5D-5F / ; ] ^ _ - %x61-7A ; a-z - %x7C-10FFFF ; |}~ ... - escaped-literal = escaped-char / (escape %x60) - -A literal expression is an expression that allows arbitrary JSON objects to be -specified. This is useful in filter expressions as well as multi select hashes -(to create arbitrary key value pairs), but is allowed anywhere an expression is -allowed. The specification includes the ABNF for JSON, implementations should -use an existing JSON parser to parse literal values. Note that the ``\``` -character must now be escaped in a ``json-value`` which means implementations -need to handle this case before passing the resulting string to a JSON parser. - -Note the second literal rule. This is used to specify a string such that -double quotes do not have to be included. This means that the literal -expression ``\`"foo"\``` is equivalent to ``\`foo\```. - - -Examples --------- - -:: - - search(`foo`, "anything") -> "foo" - search(`"foo"`, "anything") -> "foo" - search(`[1, 2]`, "anything") -> [1, 2] - search(`true`, "anything") -> true - search(`{"a": "b"}`.a, "anything") -> "b" - search({first: a, type: `mytype`}, {"a": "b", "c": "d"}) -> {"first": "b", "type": "mytype"} - - -Filter Expressions -================== - -:: - - list-filter-expr = expression comparator expression - comparator = "<" / "<=" / "==" / ">=" / ">" / "!=" - -A filter expression provides a way to select JSON elements based on a -comparison to another expression. A filter expression is evaluated as follows: -for each element in an array evaluate the ``list-filter-expr`` against the -element. If the expression evaluates to ``true``, the item (in its entirety) is -added to the result list. Otherwise it is excluded from the result list. A -filter expression is only defined for a JSON array. Attempting to evaluate a -filter expression against any other type will return ``null``. - -Comparison Operators --------------------- - -The following operations are supported: - -* ``==``, tests for equality. -* ``!=``, tests for inequality. -* ``<``, less than. -* ``<=``, less than or equal to. -* ``>``, greater than. -* ``>=``, greater than or equal to. - -The behavior of each operation is dependent on the type of each evaluated -expression. - -The comparison semantics for each operator are defined below based on -the corresponding JSON type: - -Equality Operators -~~~~~~~~~~~~~~~~~~ - -For ``string/number/true/false/null`` types, equality is an exact match. A -``string`` is equal to another ``string`` if they they have the exact sequence -of code points. The literal values ``true/false/null`` are only equal to their -own literal values. Two JSON objects are equal if they have the same set of -keys and values (given two JSON objects ``x`` and ``y``, for each key value -pair ``(i, j)`` in ``x``, there exists an equivalent pair ``(i, j)`` in ``y``). -Two JSON arrays are equal if they have equal elements in the same order (given -two arrays ``x`` and ``y``, for each ``i`` from ``0`` until ``length(x)``, -``x[i] == y[i]``). - -Ordering Operators -~~~~~~~~~~~~~~~~~~ - -Ordering operators ``>, >=, <, <=`` are **only** valid for numbers. -Evaluating any other type with a comparison operator will yield a ``null`` -value, which will result in the element being excluded from the result list. -For example, given:: - - search('foo[?a [{"bar": 10}] - search([?bar==`10`], [{"bar": 1}, {"bar": 10}]}) -> [{"bar": 10}] - search(foo[?a==b], {"foo": [{"a": 1, "b": 2}, {"a": 2, "b": 2}]}) -> [{"a": 2, "b": 2}] - - -.. _RFC4234: http://tools.ietf.org/html/rfc4234 - - -Functions Expressions -===================== - -:: - - function-expression = unquoted-string ( - no-args / - one-or-more-args ) - no-args = "(" ")" - one-or-more-args = "(" ( function-arg *( "," function-arg ) ) ")" - function-arg = expression / current-node / expression-type - current-node = "@" - expression-type = "&" expression - - -Functions allow users to easily transform and filter data in JMESPath -expressions. - -Data Types ----------- - -In order to support functions, a type system is needed. The JSON types are used: - -* number (integers and double-precision floating-point format in JSON) -* string -* boolean (``true`` or ``false``) -* array (an ordered, sequence of values) -* object (an unordered collection of key value pairs) -* null - -There is also an additional type that is not a JSON type that's used in -JMESPath functions: - -* expression (denoted by ``&expression``) - -current-node ------------- - -The ``current-node`` token can be used to represent the current node being -evaluated. The ``current-node`` token is useful for functions that require the -current node being evaluated as an argument. For example, the following -expression creates an array containing the total number of elements in the -``foo`` object followed by the value of ``foo["bar"]``. - -:: - - foo[].[count(@), bar] - -JMESPath assumes that all function arguments operate on the current node unless -the argument is a ``literal`` or ``number`` token. Because of this, an -expression such as ``@.bar`` would be equivalent to just ``bar``, so the -current node is only allowed as a bare expression. - - -current-node state -~~~~~~~~~~~~~~~~~~ - -At the start of an expression, the value of the current node is the data -being evaluated by the JMESPath expression. As an expression is evaluated, the -value the the current node represents MUST change to reflect the node currently -being evaluated. When in a projection, the current node value must be changed -to the node currently being evaluated by the projection. - -Function Evaluation -------------------- - -Functions are evaluated in applicative order. Each argument must be an -expression, each argument expression must be evaluated before evaluating the -function. The function is then called with the evaluated function arguments. -The result of the ``function-expression`` is the result returned by the -function call. If a ``function-expression`` is evaluated for a function that -does not exist, the JMESPath implementation must indicate to the caller that an -``unknown-function`` error occurred. How and when this error is raised is -implementation specific, but implementations should indicate to the caller that -this specific error occurred. - -Functions can either have a specific arity or be variadic with a minimum -number of arguments. If a ``function-expression`` is encountered where the -arity does not match or the minimum number of arguments for a variadic function -is not provided, then implementations must indicate to the caller than an -``invalid-arity`` error occurred. How and when this error is raised is -implementation specific. - -Each function signature declares the types of its input parameters. If any -type constraints are not met, implementations must indicate that an -``invalid-type`` error occurred. - -In order to accommodate type constraints, functions are provided to convert -types to other types (``to_string``, ``to_number``) which are defined below. -No explicit type conversion happens unless a user specifically uses one of -these type conversion functions. - -Function expressions are also allowed as the child element of a sub expression. -This allows functions to be used with projections, which can enable functions -to be applied to every element in a projection. For example, given the input -data of ``["1", "2", "3", "notanumber", true]``, the following expression can -be used to convert (and filter) all elements to numbers:: - - search([].to_number(@), ``["1", "2", "3", "notanumber", true]``) -> [1, 2, 3] - -This provides a simple mechanism to explicitly convert types when needed. - -Built-in Functions -================== - -JMESPath has various built-in functions that operate on different -data types, documented below. Each function below has a signature -that defines the expected types of the input and the type of the returned -output:: - - return_type function_name(type $argname) - return_type function_name2(type1|type2 $argname) - -If a function can accept multiple types for an input value, then the -multiple types are separated with ``|``. If the resolved arguments do not -match the types specified in the signature, an ``invalid-type`` error occurs. - -The ``array`` type can further specify requirements on the type of the elements -if they want to enforce homogeneous types. The subtype is surrounded by -``[type]``, for example, the function signature below requires its input -argument resolves to an array of numbers:: - - return_type foo(array[number] $argname) - -As a shorthand, the type ``any`` is used to indicate that the argument can be -of any type (``array|object|number|string|boolean|null``). - -Similarly how arrays can specify a type within a list using the -``array[type]`` syntax, expressions can specify their resolved type using -``expression->type`` syntax. This means that the resolved type of the function -argument must be an expression that itself will resolve to ``type``. - -The first function below, ``abs`` is discussed in detail to demonstrate the -above points. Subsequent function definitions will not include these details -for brevity, but the same rules apply. - -.. note:: - - All string related functions are defined on the basis of Unicode code - points; they do not take normalization into account. - - -abs ---- - -:: - - number abs(number $value) - -Returns the absolute value of the provided argument. The signature indicates -that a number is returned, and that the input argument ``$value`` **must** -resolve to a number, otherwise a ``invalid-type`` error is triggered. - -Below is a worked example. Given:: - - {"foo": -1, "bar": "2"} - -Evaluating ``abs(foo)`` works as follows: - -1. Evaluate the input argument against the current data:: - - search(foo, {"foo": -1, "bar": 2"}) -> -1 - -2. Validate the type of the resolved argument. In this case - ``-1`` is of type ``number`` so it passes the type check. - -3. Call the function with the resolved argument:: - - abs(-1) -> 1 - -4. The value of ``1`` is the resolved value of the function expression - ``abs(foo)``. - - -Below is the same steps for evaluating ``abs(bar)``: - -1. Evaluate the input argument against the current data:: - - search(bar, {"foo": -1, "bar": 2"}) -> "2" - -2. Validate the type of the resolved argument. In this case - ``"2"`` is of type ``string`` so we immediately indicate that - an ``invalid-type`` error occurred. - - -As a final example, here is the steps for evaluating ``abs(to_number(bar))``: - -1. Evaluate the input argument against the current data:: - - search(to_number(bar), {"foo": -1, "bar": "2"}) - -2. In order to evaluate the above expression, we need to evaluate - ``to_number(bar)``:: - - search(bar, {"foo": -1, "bar": "2"}) -> "2" - # Validate "2" passes the type check for to_number, which it does. - to_number("2") -> 2 - - Note that `to_number`_ is defined below. - -3. Now we can evaluate the original expression:: - - search(to_number(bar), {"foo": -1, "bar": "2"}) -> 2 - -4. Call the function with the final resolved value:: - - abs(2) -> 2 - -5. The value of ``2`` is the resolved value of the function expression - ``abs(to_number(bar))``. - - -.. list-table:: Examples - :header-rows: 1 - - * - Expression - - Result - * - ``abs(1)`` - - 1 - * - ``abs(-1)`` - - 1 - * - ``abs(`abc`)`` - - ```` - - -avg ---- - -:: - - number avg(array[number] $elements) - -Returns the average of the elements in the provided array. - -An empty array will produce a return value of null. - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``[10, 15, 20]`` - - ``avg(@)`` - - 15 - * - ``[10, false, 20]`` - - ``avg(@)`` - - ```` - * - ``[false]`` - - ``avg(@)`` - - ```` - * - ``false`` - - ``avg(@)`` - - ```` - - -contains --------- - -:: - - boolean contains(array|string $subject, any $search) - -Returns ``true`` if the given ``$subject`` contains the provided ``$search`` -string. - -If ``$subject`` is an array, this function returns true if one of the elements -in the array is equal to the provided ``$search`` value. - -If the provided ``$subject`` is a string, this function returns true if -the string contains the provided ``$search`` argument. - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - n/a - - ``contains(`foobar`, `foo`)`` - - ``true`` - * - n/a - - ``contains(`foobar`, `not`)`` - - ``false`` - * - n/a - - ``contains(`foobar`, `bar`)`` - - ``true`` - * - n/a - - ``contains(`false`, `bar`)`` - - ```` - * - n/a - - ``contains(`foobar`, 123)`` - - ``false`` - * - ``["a", "b"]`` - - ``contains(@, `a`)`` - - ``true`` - * - ``["a"]`` - - ``contains(@, `a`)`` - - ``true`` - * - ``["a"]`` - - ``contains(@, `b`)`` - - ``false`` - -ceil ----- - -:: - - number ceil(number $value) - -Returns the next highest integer value by rounding up if necessary. - -.. list-table:: Examples - :header-rows: 1 - - * - Expression - - Result - * - ``ceil(`1.001`)`` - - 2 - * - ``ceil(`1.9`)`` - - 2 - * - ``ceil(`1`)`` - - 1 - * - ``ceil(`abc`)`` - - ``null`` - - -ends_with ---------- - -:: - - boolean ends_with(string $subject, string $prefix) - -Returns ``true`` if the ``$subject`` ends with the ``$prefix``, otherwise this -function returns ``false``. - - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``foobarbaz`` - - ``ends_with(@, ``baz``)`` - - ``true`` - * - ``foobarbaz`` - - ``ends_with(@, ``foo``)`` - - ``false`` - * - ``foobarbaz`` - - ``ends_with(@, ``z``)`` - - ``true`` - - -floor ------ - -:: - - number floor(number $value) - -Returns the next lowest integer value by rounding down if necessary. - -.. list-table:: Examples - :header-rows: 1 - - * - Expression - - Result - * - ``floor(`1.001`)`` - - 1 - * - ``floor(`1.9`)`` - - 1 - * - ``floor(`1`)`` - - 1 - - -join ----- - -:: - - string join(string $glue, array[string] $stringsarray) - -Returns all of the elements from the provided ``$stringsarray`` array joined -together using the ``$glue`` argument as a separator between each. - - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``["a", "b"]`` - - ``join(`, `, @)`` - - "a, b" - * - ``["a", "b"]`` - - ``join(````, @)`` - - "ab" - * - ``["a", false, "b"]`` - - ``join(`, `, @)`` - - ```` - * - ``[false]`` - - ``join(`, `, @)`` - - ```` - - -keys ----- - -:: - - array keys(object $obj) - -Returns an array containing the keys of the provided object. - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``{"foo": "baz", "bar": "bam"}`` - - ``keys(@)`` - - ``["foo", "bar"]`` - * - ``{}`` - - ``keys(@)`` - - ``[]`` - * - ``false`` - - ``keys(@)`` - - ```` - * - ``[b, a, c]`` - - ``keys(@)`` - - ```` - - -length ------- - -:: - - number length(string|array|object $subject) - -Returns the length of the given argument using the following types rules: - -1. string: returns the number of code points in the string -2. array: returns the number of elements in the array -3. object: returns the number of key-value pairs in the object - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - n/a - - ``length(`abc`)`` - - 3 - * - "current" - - ``length(@)`` - - 7 - * - "current" - - ``length(not_there)`` - - ```` - * - ``["a", "b", "c"]`` - - ``length(@)`` - - 3 - * - ``[]`` - - ``length(@)`` - - 0 - * - ``{}`` - - ``length(@)`` - - 0 - * - ``{"foo": "bar", "baz": "bam"}`` - - ``length(@)`` - - 2 - - -max ---- - -:: - - number max(array[number]|array[string] $collection) - -Returns the highest found number in the provided array argument. - -An empty array will produce a return value of null. - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``[10, 15]`` - - ``max(@)`` - - 15 - * - ``["a", "b"]`` - - ``max(@)`` - - "b" - * - ``["a", 2, "b"]`` - - ``max(@)`` - - ```` - * - ``[10, false, 20]`` - - ``max(@)`` - - ```` - - -max_by ------- - -:: - - max_by(array elements, expression->number|expression->string expr) - -Return the maximum element in an array using the expression ``expr`` as the -comparison key. The entire maximum element is returned. -Below are several examples using the ``people`` array (defined above) as the -given input. - - -.. list-table:: Examples - :header-rows: 1 - - * - Expression - - Result - * - ``max_by(people, &age)`` - - ``{"age": 50, "age_str": "50", "bool": false, "name": "d"}`` - * - ``max_by(people, &age).age`` - - 50 - * - ``max_by(people, &to_number(age_str))`` - - ``{"age": 50, "age_str": "50", "bool": false, "name": "d"}`` - * - ``max_by(people, &age_str)`` - - - * - ``max_by(people, age)`` - - - - -min ---- - -:: - - number min(array[number]|array[string] $collection) - -Returns the lowest found number in the provided ``$collection`` argument. - - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``[10, 15]`` - - ``min(@)`` - - 10 - * - ``["a", "b"]`` - - ``min(@)`` - - "a" - * - ``["a", 2, "b"]`` - - ``min(@)`` - - ```` - * - ``[10, false, 20]`` - - ``min(@)`` - - ```` - - -min_by ------- - -:: - - min_by(array elements, expression->number|expression->string expr) - -Return the minimum element in an array using the expression ``expr`` as the -comparison key. The entire maximum element is returned. -Below are several examples using the ``people`` array (defined above) as the -given input. - - -.. list-table:: Examples - :header-rows: 1 - - * - Expression - - Result - * - ``min_by(people, &age)`` - - ``{"age": 10, "age_str": "10", "bool": true, "name": 3}`` - * - ``min_by(people, &age).age`` - - 10 - * - ``min_by(people, &to_number(age_str))`` - - ``{"age": 10, "age_str": "10", "bool": true, "name": 3}`` - * - ``min_by(people, &age_str)`` - - ```` - * - ``min_by(people, age)`` - - ```` - - -.. _not_null: - -not_null --------- - -:: - - any not_null(any $argument [, any $...]) - -Returns the first argument that does not resolve to ``null``. This function -accepts one or more arguments, and will evaluate them in order until a -non null argument is encountered. If all arguments values resolve to ``null``, -then a value of ``null`` is returned. - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``{"a": null, "b": null, "c": [], "d": "foo"}`` - - ``not_null(no_exist, a, b, c, d)`` - - [] - * - ``{"a": null, "b": null, "c": [], "d": "foo"}`` - - ``not_null(a, b, `null`, d, c)`` - - ``"foo"`` - * - ``{"a": null, "b": null, "c": [], "d": "foo"}`` - - ``not_null(a, b)`` - - ``null`` - - -reverse -------- - -:: - - array reverse(string|array $argument) - -Reverses the order of the ``$argument``. - - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``[0, 1, 2, 3, 4]`` - - ``reverse(@)`` - - ``[4, 3, 2, 1, 0]`` - * - ``[] - - ``reverse(@)`` - - ``[]`` - * - ``["a", "b", "c", 1, 2, 3]`` - - ``reverse(@)`` - - ``[3, 2, 1, "c", "b", "a"]`` - * - ``"abcd`` - - ``reverse(@)`` - - ``dcba`` - - -sort ----- - -:: - - array sort(array[number]|array[string] $list) - -This function accepts an array ``$list`` argument and returns the sorted -elements of the ``$list`` as an array. - -The array must be a list of strings or numbers. Sorting strings is based on -code points. Locale is not taken into account. - - - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``[b, a, c]`` - - ``sort(@)`` - - ``[a, b, c]`` - * - ``[1, a, c]`` - - ``sort(@)`` - - ``[1, a, c]`` - * - ``[false, [], null]`` - - ``sort(@)`` - - ``[[], null, false]`` - * - ``[[], {}, false]`` - - ``sort(@)`` - - ``[{}, [], false]`` - * - ``{"a": 1, "b": 2}`` - - ``sort(@)`` - - ``null`` - * - ``false`` - - ``sort(@)`` - - ``null`` - - -sort_by -------- - -:: - - sort_by(array elements, expression->number|expression->string expr) - -Sort an array using an expression ``expr`` as the sort key. -Below are several examples using the ``people`` array (defined above) as the -given input. ``sort_by`` follows the same sorting logic as the ``sort`` -function. - - -.. list-table:: Examples - :header-rows: 1 - - * - Expression - - Result - * - ``sort_by(people, &age)[].age`` - - ``[10, 20, 30, 40, 50]`` - * - ``sort_by(people, &age)[0]`` - - ``{"age": 10, "age_str": "10", "bool": true, "name": 3}`` - * - ``sort_by(people, &to_number(age_str))[0]`` - - ``{"age": 10, "age_str": "10", "bool": true, "name": 3}`` - - -starts_with ------------ - -:: - - boolean starts_with(string $subject, string $prefix) - -Returns ``true`` if the ``$subject`` starts with the ``$prefix``, otherwise -this function returns ``false``. - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``foobarbaz`` - - ``starts_with(@, ``foo``)`` - - ``true`` - * - ``foobarbaz`` - - ``starts_with(@, ``baz``)`` - - ``false`` - * - ``foobarbaz`` - - ``starts_with(@, ``f``)`` - - ``true`` - - -sum ---- - -:: - - number sum(array[number] $collection) - -Returns the sum of the provided array argument. - -An empty array will produce a return value of 0. - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``[10, 15]`` - - ``sum(@)`` - - 25 - * - ``[10, false, 20]`` - - ``max(@)`` - - ```` - * - ``[10, false, 20]`` - - ``sum([].to_number(@))`` - - 30 - * - ``[]`` - - ``sum(@)`` - - 0 - - -to_string ---------- - -:: - - string to_string(any $arg) - -* string - Returns the passed in value. -* number/array/object/boolean - The JSON encoded value of the object. The - JSON encoder should emit the encoded JSON value without adding any additional - new lines. - - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``null`` - - ``to_string(`2`)`` - - ``"2"`` - - -to_number ---------- - -:: - - number to_number(any $arg) - -* string - Returns the parsed number. Any string that conforms to the - ``json-number`` production is supported. Note that the floating number - support will be implementation specific, but implementations should support - at least IEEE 754-2008 binary64 (double precision) numbers, as this is - generally available and widely used. -* number - Returns the passed in value. -* array - null -* object - null -* boolean - null -* null - null - - -type ----- - -:: - - string type(array|object|string|number|boolean|null $subject) - -Returns the JavaScript type of the given ``$subject`` argument as a string -value. - -The return value MUST be one of the following: - -* number -* string -* boolean -* array -* object -* null - - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - "foo" - - ``type(@)`` - - "string" - * - ``true`` - - ``type(@)`` - - "boolean" - * - ``false`` - - ``type(@)`` - - "boolean" - * - ``null`` - - ``type(@)`` - - "null" - * - 123 - - ``type(@)`` - - number - * - 123.05 - - ``type(@)`` - - number - * - ``["abc"]`` - - ``type(@)`` - - "array" - * - ``{"abc": "123"}`` - - ``type(@)`` - - "object" - - -values ------- - -:: - - array values(object $obj) - -Returns the values of the provided object. - - -.. list-table:: Examples - :header-rows: 1 - - * - Given - - Expression - - Result - * - ``{"foo": "baz", "bar": "bam"}`` - - ``values(@)`` - - ``["baz", "bam"]`` - * - ``["a", "b"]`` - - ``values(@)`` - - ```` - * - ``false`` - - ``values(@)`` - - ```` - - -Pipe Expressions -================ - -:: - - pipe-expression = expression "|" expression - -A pipe expression combines two expressions, separated by the ``|`` character. -It is similar to a ``sub-expression`` with two important distinctions: - -1. Any expression can be used on the right hand side. A ``sub-expression`` - restricts the type of expression that can be used on the right hand side. -2. A ``pipe-expression`` **stops projections on the left hand side for - propagating to the right hand side**. If the left expression creates a - projection, it does **not** apply to the right hand side. - -For example, given the following data:: - - {"foo": [{"bar": ["first1", "second1"]}, {"bar": ["first2", "second2"]}]} - -The expression ``foo[*].bar`` gives the result of:: - - [ - [ - "first1", - "second1" - ], - [ - "first2", - "second2" - ] - ] - -The first part of the expression, ``foo[*]``, creates a projection. At this -point, the remaining expression, ``bar`` is projected onto each element of the -list created from ``foo[*]``. If you project the ``[0]`` expression, you will -get the first element from each sub list. The expression ``foo[*].bar[0]`` -will return:: - - ["first1", "first2"] - -If you instead wanted *only* the first sub list, ``["first1", "second1"]``, you -can use a ``pipe-expression``:: - - foo[*].bar[0] -> ["first1", "first2"] - foo[*].bar | [0] -> ["first1", "second1"] - - -Examples --------- - -:: - - search(foo | bar, {"foo": {"bar": "baz"}}) -> "baz" - search(foo[*].bar | [0], { - "foo": [{"bar": ["first1", "second1"]}, - {"bar": ["first2", "second2"]}]}) -> ["first1", "second1"] - search(foo | [0], {"foo": [0, 1, 2]}) -> [0] diff --git a/requirements-docs.txt b/requirements-docs.txt deleted file mode 100644 index b66d0369..00000000 --- a/requirements-docs.txt +++ /dev/null @@ -1,3 +0,0 @@ --r requirements.txt -Sphinx==1.2b3 -guzzle-sphinx-theme==0.3.1 diff --git a/scripts/bumpversion b/scripts/bumpversion index 66d8f09b..553729ab 100755 --- a/scripts/bumpversion +++ b/scripts/bumpversion @@ -3,11 +3,6 @@ import os import argparse from subprocess import check_call -try: - input = raw_input -except NameError: - pass - def open_file(filename, mode='r'): # relative open a file from the root project dir. @@ -19,7 +14,6 @@ def open_file(filename, mode='r'): def bump_version(version): - update_sphinx_conf(version) update_setup_py(version) update_jmespath__init__(version) show_git_diff() @@ -38,16 +32,6 @@ def update_setup_py(version): f.write(''.join(lines)) -def update_sphinx_conf(version): - with open_file('docs/conf.py') as f: - lines = f.readlines() - for i, line in enumerate(lines): - if line.startswith('release = '): - lines[i] = "release = '%s'\n" % version - with open_file('docs/conf.py', 'w') as f: - f.write(''.join(lines)) - - def update_jmespath__init__(version): with open_file('jmespath/__init__.py') as f: lines = f.readlines() diff --git a/scripts/release b/scripts/release index 4eacad2e..ba3451db 100755 --- a/scripts/release +++ b/scripts/release @@ -2,7 +2,7 @@ """Script to manage releases. * Create release branches -* Version bump setup.py, docs/conf.py, etc. +* Version bump setup.py, etc. * Tag the releases * Merge to master * Push everything up to github. @@ -19,11 +19,6 @@ Usage:: import argparse from subprocess import check_call, check_output -try: - input = raw_input -except NameError: - pass - def run(command): print("Running:", command)