diff --git a/README.md b/README.md index 8ef1c23d..a95043fc 100644 --- a/README.md +++ b/README.md @@ -5,4 +5,4 @@ [![PEP compatible](http://pepkit.github.io/img/PEP-compatible-green.svg)](http://pepkit.github.io) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) -[PEP](http://pepkit.github.io) validation tool based on [jsonschema](https://github.com/Julian/jsonschema). See [documentation](http://eido.databio.org) for usage. +[PEP](https://pep.databio.org) validation tool based on [jsonschema](https://github.com/Julian/jsonschema). See [documentation](http://pep.databio.org/eido) for usage. diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index 8b304309..00000000 --- a/docs/README.md +++ /dev/null @@ -1,43 +0,0 @@ -eido -![Run pytests](https://github.com/pepkit/eido/workflows/Run%20pytests/badge.svg) -[![codecov](https://codecov.io/gh/pepkit/eido/branch/master/graph/badge.svg)](https://codecov.io/gh/pepkit/eido) -[![PEP compatible](http://pepkit.github.io/img/PEP-compatible-green.svg)](http://pepkit.github.io) -[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) - -## Introduction - -Eido is used to 1) validate or 2) convert format of sample metadata. Sample metadata is stored according to the standard [PEP specification](https://pep.databio.org). For validation, eido is based on [JSON Schema](https://json-schema.org) and extends it with new features, like required input files. You can [write your own schema](writing-a-schema.md) for your pipeline and use eido to validate sample metadata. For conversion, [eido filters](filters.md) convert sample metadata input into any output format, including [custom filters](writing-a-filter.md). - -## Why do we need eido? - -Data-intensive bioinformatics projects often include metadata describing a set of samples. When it comes to handling such sample metadata, there are two common challenges that eido solves: - - - -- **Validation**. Tool authors use eido to specify and describe required input sample attributes. Input sample attributes are described with a schema, and eido validates the sample metadata to ensure it satisfies the tool's needs. Eido uses [JSON Schema](https://json-schema.org/), which annotates and validates JSON. JSON schema alone is great for validating JSON, but bioinformatics sample metadata is more complicated, so eido provides additional capability and features tailored to bioinformatics projects listed below. - - - -- **Format conversion**. Tools often require sample metadata in a specific format. Eido filters take a metadata in standard PEP format and convert it to any desired output format. Filters can be either built-in or custom. This allows a single sample metadata source to be used for multiple downstream analyses. - -## Eido validation features - -An eido schema is written using the JSON Schema vocabulary, plus a few additional features: - -1. **required input files**. Eido adds `required_files`, which allows a schema author to specify which attributes must point to files that exist. -2. **optional input files**. `files` specifies which attributes point to files that may or may not exist. -3. **project and sample validation**. Eido validates project attributes separately from sample attributes. -4. **schema imports**. Eido adds an `imports` section for schemas that should be validated prior to this schema -5. **automatic multi-value support**. Eido validates successfully for singular or plural sample attributes for strings, booleans, and numbers. This accommodates the PEP subsample_table feature. - -## How to use eido - -- [Use eido to validate data from the command line](cli.md) -- [Use eido to validate data from Python](demo.md) -- [Write your own schema](writing-a-schema.md) - ---- - -## Why the name 'eido'? - -*Eidos* is a Greek term meaning *form*, *essence*, or *type* (see Plato's [Theory of Forms](https://en.wikipedia.org/wiki/Theory_of_forms)). Schemas are analogous to *forms*, and eido tests claims that an instance is of a particular form. Eido also helps *change* forms using filters. diff --git a/docs/api_docs.md b/docs/api_docs.md deleted file mode 100644 index dd47fac1..00000000 --- a/docs/api_docs.md +++ /dev/null @@ -1,214 +0,0 @@ -Final targets: EidoValidationError, convert_project, get_available_pep_filters, get_input_files_size, inspect_project, read_schema, validate_config, validate_input_files, validate_project, validate_sample - - - - - -# Package `eido` Documentation - - -Project configuration - -## Class `EidoValidationError` -Object was not validated successfully according to schema. - - -```python -def __init__(self, message, errors_by_type) -``` - -Initialize self. See help(type(self)) for accurate signature. - - - -```python -def validate_project(project, schema) -``` - -Validate a project object against a schema -#### Parameters: - -- `project` (`peppy.Project`): a project object to validate -- `schema` (`str | dict`): schema dict to validate against or a path to onefrom the error. Useful when used ith large projects - - - - -```python -def validate_sample(project, sample_name, schema) -``` - -Validate the selected sample object against a schema -#### Parameters: - -- `project` (`peppy.Project`): a project object to validate -- `sample_name` (`str | int`): name or index of the sample to validate -- `schema` (`str | dict`): schema dict to validate against or a path to one - - - - -```python -def validate_config(project, schema) -``` - -Validate the config part of the Project object against a schema -#### Parameters: - -- `project` (`peppy.Project`): a project object to validate -- `schema` (`str | dict`): schema dict to validate against or a path to one - - - - -```python -def read_schema(schema) -``` - -Safely read schema from YAML-formatted file. - -If the schema imports any other schemas, they will be read recursively. -#### Parameters: - -- `schema` (`str | Mapping`): path to the schema fileor schema in a dict form - - -#### Returns: - -- `list[dict]`: read schemas - - -#### Raises: - -- `TypeError`: if the schema arg is neither a Mapping nor a file path orif the 'imports' sections in any of the schemas is not a list - - - - -```python -def inspect_project(p, sample_names=None, max_attr=10) -``` - -Print inspection info: Project or, if sample_names argument is provided, matched samples -#### Parameters: - -- `p` (`peppy.Project`): project to inspect -- `sample_names` (`Iterable[str]`): list of samples to inspect -- `max_attr` (`int`): max number of sample attributes to display - - - - -```python -def get_available_pep_filters() -``` - -Get a list of available target formats -#### Returns: - -- `List[str]`: a list of available formats - - - - -```python -def convert_project(prj, target_format, plugin_kwargs=None) -``` - -Convert a `peppy.Project` object to a selected format -#### Parameters: - -- `prj` (`peppy.Project`): a Project object to convert -- `plugin_kwargs` (`dict`): kwargs to pass to the plugin function -- `target_format` (`str`): the format to convert the Project object to - - -#### Raises: - -- `EidoFilterError`: if the requested filter is not defined - - - - -```python -def validate_input_files(project, schemas, sample_name=None) -``` - -Determine which of the required and optional files are missing. - -The names of the attributes that are required and/or deemed as inputs -are sourced from the schema, more specifically from `required_files` -and `files` sections in samples section: -- If any of the required files are missing, this function raises an error. -- If any of the optional files are missing, the function raises a warning. -Note, this function also performs Sample object validation with jsonschema. -#### Parameters: - -- `project` (`peppy.Project`): project that defines the samples to validate -- `schema` (`str | dict`): schema dict to validate against or a path to one -- `sample_name` (`str | int`): name or index of the sample to validate. If None,validate all samples in the project - - -#### Raises: - -- `PathAttrNotFoundError`: if any required sample attribute is missing - - - - -```python -def get_input_files_size(sample, schema) -``` - -Determine which of this Sample's required attributes/files are missing and calculate sizes of the files (inputs). - -The names of the attributes that are required and/or deemed as inputs -are sourced from the schema, more specifically from required_input_attrs -and input_attrs sections in samples section. Note, this function does -perform actual Sample object validation with jsonschema. -#### Parameters: - -- `sample` (`peppy.Sample`): sample to investigate -- `schema` (`list[dict] | str`): schema dict to validate against or a path to one - - -#### Returns: - -- `dict`: dictionary with validation data, i.e missing,required_inputs, all_inputs, input_file_size - - -#### Raises: - -- `ValidationError`: if any required sample attribute is missing - - - - - - - -*Version Information: `eido` v0.2.2-dev, generated by `lucidoc` v0.4.4* diff --git a/docs/autodoc_build/eido.md b/docs/autodoc_build/eido.md deleted file mode 100644 index 27504562..00000000 --- a/docs/autodoc_build/eido.md +++ /dev/null @@ -1,108 +0,0 @@ - - - - - -# Package `eido` Documentation - -```python -def validate_project(project, schema) -``` - -Validate a project object against a schema -#### Parameters: - -- `project` (`peppy.Sample`): a project object to validate -- `schema` (`str | dict`): schema dict to validate against or a path to one - - - -```python -def validate_sample(project, sample_name, schema) -``` - -Validate the selected sample object against a schema -#### Parameters: - -- `project` (`peppy.Project`): a project object to validate -- `sample_name` (`str | int`): name or index of the sample to validate -- `schema` (`str | dict`): schema dict to validate against or a path to one - - -```python -def validate_config(project, schema) -``` - -Validate the config part of the Project object against a schema -#### Parameters: - -- `project` (`peppy.Project`): a project object to validate -- `schema` (`str | dict`): schema dict to validate against or a path to one - - -```python -def read_schema(schema) -``` - -Safely read schema from YAML-formatted file. - -If the schema imports any other schemas, they will be read recursively. -#### Parameters: - -- `schema` (`str | Mapping`): path to the schema fileor schema in a dict form - - -#### Returns: - -- `list[dict]`: read schemas - - -#### Raises: - -- `TypeError`: if the schema arg is neither a Mapping nor a file path orif the 'imports' sections in any of the schemas is not a list - - - - -```python -def inspect_project(p, sample_names=None, max_attr=10) -``` - -Print inspection info: Project or, if sample_names argument is provided, matched samples -#### Parameters: - -- `p` (`peppy.Project`): project to inspect -- `sample_names` (`Iterable[str]`): list of samples to inspect -- `max_attr` (`int`): max number of sample attributes to display - - - - - - - -*Version Information: `eido` v0.1.0, generated by `lucidoc` v0.4.2* \ No newline at end of file diff --git a/docs/changelog.md b/docs/changelog.md deleted file mode 100644 index aef4f8c3..00000000 --- a/docs/changelog.md +++ /dev/null @@ -1,141 +0,0 @@ -# Changelog - -This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) and [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) format. - -## [0.2.2] - 2023-11-16 - -### Changed -- remove unused `exclude-case` from CLI. Fixes #65 - -## [0.2.1] - 2023-07-05 - -### Changed -- printing project to logger.debug - -## [0.2.0] - 2023-06-21 - -### Added -- CLI options for modulating peppy project (#50) - -### Fixed -- Rewrote history to remove large files committed by mistake -- You can now check for existing of files in subsample table (#26) - -### Changed -- All validation functions now use similar error-raising behavior -- Validation functions now return all individual error objects grouped by type - - -## [0.1.9] - 2022-09-12 - -### Fixed -- CSV filter bug - -### Added -- New test cases - -## [0.1.8] - 2022-08-29 -### Changed -- the way of merging tables for multiline output format from eido convert - -### Added -- better architecture for output formatters that goes well with **open-closed principle** -- using mock in some testcases -- test data in the format that was causing the errors previously - -### Fixed -- passing plugin keyword arguments to `run_filter` function -- saving output file will now work for path like `file.txt`, no need to pass full path - - -## [0.1.7] - 2022-08-11 -### Changed -- When a validation fails, `eido` will now return all errors instead of just the first one it finds. - -## [0.1.6] - 2022-05-16 -### Added -- a possibility to set a custom sample table index with `-s/--st-index` option -- an option to see filters docs via CLI: `eido filters -f ` -- PEP filters now return their conversion result for progrommatic use. -- PEP filters can write to files. -- A filter can write multiple outputs to multiple files using the `paths` keyword arg. - -### Fixed -- Some error messages with incorrectly defined schemas. -- 'required' attribute is no longer required in schema - -### Changed -- Moved all `eido filter` functionality into the `eido convert` command for simplicity. This way, a single top-level command namespace holds all related functionality. Filters are still EXPERIMENTAL. - -## [0.1.5] - 2021-04-15 -### Added -- `eido convert` converts the provided PEP to a specified format (EXPERIMENTAL! may change in future versions) -- `eido filter` lists available filters in current environment (EXPERIMENTAL! may change in future versions) -- built-in plugins (EXPERIMENTAL! may change in future versions): - - `basic_pep_filter` - - `yaml_pep_filter` - - `csv_pep_filter` - - `yaml_samples_pep_filter` - -### Changed -- in `validate_inputs` function sample attributes are first validated for existence before their values' existence is checked - -## [0.1.4] - 2021-03-14 -### Changed -- update schema preprocessing - -## [0.1.3] - 2020-10-07 -### Changed -- `validate_inputs` function now returns a dictionary with validation data, i.e missing, required_inputs, all_inputs, input_file_size rather than a list of missing files -- `validate_inputs` function does not modify `Sample` objects - -## [0.1.2] - 2020-08-06 -### Added -- license in the package source distribution - -## [0.1.1] - 2020-05-27 -### Changed -- documentation updates -- CLI behavior when no subcommand provided; [#20](https://github.com/pepkit/eido/issues/20) - -## [0.1.0] - 2020-05-26 -### Added -- automatic support for subsamples for sample the following property types: - - `string` - - `boolean` - - `numeric` -- `eido inspect` CLI command -- schema importing functionality (via top level `imports` key) -- exported functions: - - `validate_inputs` - - `inspect_project` - - `read_schema` - -### Changed -- previous CLI `eido` functionality moved to `eido validate` - -## [0.0.6] - 2020-02-07 -### Changed -- CLI can accommodate URLs. - -## [0.0.5] - 2020-02-04 -### Added -- [documentation website](http://eido.databio.org/en/latest/) -- include version in the CLI help - -## [0.0.4] - 2020-01-31 -### Added -- `validate_sample` function for sample level validation -- sample validation CLI support (via `-n`/`--sample-name` argument) -- `validate_config` to facilitate samples exclusion in validation -- config validation CLI support (via `-c`/`--just-config` argument) - -## [0.0.3] - 2020-01-30 -### Added -- Option to exclude the validation case from error messages in both Python API and CLI app with `exclude_case` and `-e`/`--exclude-case`, respectively. -- include requirements in the source distribution - -## [0.0.2] - 2020-01-12 - -### Added -- Initial project release diff --git a/docs/contributing.md b/docs/contributing.md deleted file mode 100644 index 9508346b..00000000 --- a/docs/contributing.md +++ /dev/null @@ -1,5 +0,0 @@ -## Contributing - -Pull requests or issues are welcome. After adding a new feature, please add tests in the `tests` folder and run the test suite. The only additional dependencies needed beyond those for the package can be installed with: `pip install -r requirements/requirements-dev.txt`. - -Once those are installed, run the tests with `pytest` or `python setup.py test`. diff --git a/docs/example-schemas.md b/docs/example-schemas.md deleted file mode 100644 index cfea4b4e..00000000 --- a/docs/example-schemas.md +++ /dev/null @@ -1,8 +0,0 @@ -# List of schemas - -With `eido` you can create your own schema to describe the kind of projects your tool can accept. We are currently hosting schemas at [schema.databio.org](https://github.com/databio/schema.databio.org) in a GitHub repository. You can browse that repository for examples, or look at few examples here: - -- [Generic PEP2.0.0 schema](http://schema.databio.org/pep/2.0.0.yaml) -- all PEPs should validate against this schema -- [PEPPRO pipeline schema](http://schema.databio.org/pipelines/ProseqPEP.yaml) -- describes PEPs compatible with the [PEPPRO](http://peppro.databio.org) pipeline -- [PEPATAC pipeline schema](http://schema.databio.org/pipelines/pepatac.yaml) -- describes PEPs compatible with the [PEPATAC](http://pepatac.databio.org) pipeline -- [refgenie databio build schema](https://schema.databio.org/refgenie/refgenie_build.yaml) -- describes PEPs compatible with building [refgenie](http://refgenie.databio.org) assets diff --git a/docs/filters.md b/docs/filters.md deleted file mode 100644 index 21b064c1..00000000 --- a/docs/filters.md +++ /dev/null @@ -1,75 +0,0 @@ -**Filters are an experimental feature and may change in future versions of `eido`.** - -# Using eido filters - -Eido provides a CLI to convert a PEP into different output formats. These include some built-in formats, like _csv_ (which produces a processed csv file, with project/sample already modified), _yaml_, and a few others. It also provides a plugin system so that you can write your own Python functions to provide custom output formats. You access filters through the `eido convert` command. - -## View available filters - -To list available filters: - -```console -eido convert --list -``` - -You'll see some output like this. There are a few built-in filters available: - - -```console -Available filters: - - basic - - csv - - yaml - - yaml-samples -``` - -You can add to this list by [writing a custom filter](writing-a-filter.md), which will write your PEP into whatever format you need. - -## Convert a PEP into an alternative format with a filter - -To convert a PEP into an output format, do this: - -```console -eido convert config.yaml -f basic -running plugin pep -Project 'pepconvert' (/home/nsheff/code/pepconvert/config.yaml) -5 samples: WT_REP1, WT_REP2, RAP1_UNINDUCED_REP1, RAP1_UNINDUCED_REP2, RAP1_IAA_30M_REP1 -Sections: pep_version, sample_table, subsample_table -... -``` - -This *basic* format just lists the config file, the number of samples and their names, and identifies the sections in the project config file. Another format is `-f yaml`, - -```console -eido convert config.yaml -f yaml -``` - -This will output your samples in yaml format. - -### Parametrizing filters - -Filter functions are parameterizable. Some filters may request or require parameters. To learn more about a filter's parameters, use `-d` or `--describe`: `eido convert -f -d`, which displays the plugin documentation. For example: - -```console -eido convert -f yaml-samples -d - - YAML samples PEP filter, that returns only Sample object representations. - - This filter can save the YAML to file, if kwargs include `path`. - - :param peppy.Project p: a Project to run filter on -``` - -In this case, the argument `path` can be provided as an output file. Like this: - -```console -eido convert config.yaml -f yaml-samples -a path=output.yaml -``` - -More generally, the form to provide parameters is like this - -```console -eido convert config.yaml -f -a argument1=value1 argument2=value2 -``` - - diff --git a/docs/img/conversion.svg b/docs/img/conversion.svg deleted file mode 100644 index 552ba7ee..00000000 --- a/docs/img/conversion.svg +++ /dev/null @@ -1,2065 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - PEP - - - projectyaml - - - - - - - - - - - - - - csv - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - finalcsv - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - sampleyaml - - - - - - - - - - - - - eidoconvert - - diff --git a/docs/img/eido.svg b/docs/img/eido.svg deleted file mode 100644 index de00ec82..00000000 --- a/docs/img/eido.svg +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/img/eido_dark.svg b/docs/img/eido_dark.svg deleted file mode 100644 index 7fee6ddc..00000000 --- a/docs/img/eido_dark.svg +++ /dev/null @@ -1,155 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/img/eido_light.svg b/docs/img/eido_light.svg deleted file mode 100644 index 1c148ecf..00000000 --- a/docs/img/eido_light.svg +++ /dev/null @@ -1,154 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/img/no.png b/docs/img/no.png deleted file mode 100644 index 040da55c..00000000 Binary files a/docs/img/no.png and /dev/null differ diff --git a/docs/img/style.css b/docs/img/style.css deleted file mode 100644 index cf37b98b..00000000 --- a/docs/img/style.css +++ /dev/null @@ -1,157 +0,0 @@ -html, -body { - height: 100%; -} - -#vertical { - padding: 5px; -} - -#main { - overflow: auto; - padding-bottom: 40px; - padding-top: 20px; - /* must be same height as the footer */ -} - -#footer { - position: relative; - margin-top: -40px; - /* negative value of footer height */ - height: 40px; - padding-top: 5px; - padding-left: 10px; -} - -.divider-15 { - /* adds spacing 15px */ - width:90%; - min-height:1px; - margin-top:15px; - margin-bottom:15px; - margin-left:15px; - display:inline-block; - position:relative; -} - -.divider-vertical { - margin-top:15px; - /*margin-bottom:15px;*/ -} - -span { - margin-left: 5px; -} - -div.col-auto { - padding-left: 10px; - padding-right: 0px; -} - -label.col-form-label { - padding-bottom: 0px; - padding-top: 0px; -} - -.nav-item { - color: white; - font-size: 1rem; - } - -.nav-link { - color: white; - } - -.left_footer { - width: 40%; - float: left; - text-align:left; - display: inline-block; -} - -.right_footer { - width: 40%; - float: right; - text-align:right; - display: inline-block; -} - -.center_footer { - width: 20%; - overflow: hidden; - display: inline-block; - text-align: center; -} - -.wrapper { - padding-left: 30px; - padding-right: 30px; - clear: both; - position: relative; - overflow: hidden; -} - -div#navbar_links { - display: flex; -} - -div.col-12#genome-asset { - margin: auto; - max-width: 1400px; -} - -div.col-12#txt { - margin: auto; - max-width: 1400px; -} - -.asset_name { - width: 200px; -} - -.asset_desc { - width: 500px; - min-width: 250px; -} - -.actions { - min-width: 180px; - width: 180px; -} - -.size { - width: 150px; - min-width: 150px; -} - -.checksum { - width: 280px; - min-width: 280px; -} - -.container { - max-width: none; -} - -th.footer { - font-size:12px; - padding: 3px; - font-weight: bold; - text-align: center; - background-color: #464c56; - color: white; - min-width: 90px; -} - -td.footer { - font-size:12px; - padding: 3px; - text-align: center; - color: #464c56; - font-weight: bold; - font-family: Courier New; -} - -code.footer { - color:#464c56; -} diff --git a/docs/img/validation.svg b/docs/img/validation.svg deleted file mode 100644 index ad7681eb..00000000 --- a/docs/img/validation.svg +++ /dev/null @@ -1,1845 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - {x} - SCHEMA - - - - - - - - - - - - - PEP - - - yaml - - - - - - - - - - - - - - csv - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - Valid - - - - - - - eidovalidate - - diff --git a/docs/img/yes.png b/docs/img/yes.png deleted file mode 100644 index 22105cae..00000000 Binary files a/docs/img/yes.png and /dev/null differ diff --git a/docs/install.md b/docs/install.md deleted file mode 100644 index cbd54878..00000000 --- a/docs/install.md +++ /dev/null @@ -1,14 +0,0 @@ -# Installing eido - -Install from [GitHub releases](https://github.com/pepkit/eido/releases) or from PyPI using `pip`: - -- `pip install --user eido`: install into user space. -- `pip install --user --upgrade eido`: update in user space. -- `pip install eido`: install into an active virtual environment. -- `pip install --upgrade eido`: update in virtual environment. - -See if your install worked by calling `eido -h` on the command line. If the `eido` executable in not in your `$PATH`, append this to your `.bashrc` or `.profile` (or `.bash_profile` on macOS): - -```{console} -export PATH=~/.local/bin:$PATH -``` diff --git a/docs/nunjucks.js b/docs/nunjucks.js deleted file mode 100644 index 363c5369..00000000 --- a/docs/nunjucks.js +++ /dev/null @@ -1,8257 +0,0 @@ -/*! Browser bundle of nunjucks 3.2.2 */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["nunjucks"] = factory(); - else - root["nunjucks"] = factory(); -})(typeof self !== 'undefined' ? self : this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 11); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var ArrayProto = Array.prototype; -var ObjProto = Object.prototype; -var escapeMap = { - '&': '&', - '"': '"', - '\'': ''', - '<': '<', - '>': '>' -}; -var escapeRegex = /[&"'<>]/g; -var exports = module.exports = {}; - -function hasOwnProp(obj, k) { - return ObjProto.hasOwnProperty.call(obj, k); -} - -exports.hasOwnProp = hasOwnProp; - -function lookupEscape(ch) { - return escapeMap[ch]; -} - -function _prettifyError(path, withInternals, err) { - if (!err.Update) { - // not one of ours, cast it - err = new exports.TemplateError(err); - } - - err.Update(path); // Unless they marked the dev flag, show them a trace from here - - if (!withInternals) { - var old = err; - err = new Error(old.message); - err.name = old.name; - } - - return err; -} - -exports._prettifyError = _prettifyError; - -function TemplateError(message, lineno, colno) { - var err; - var cause; - - if (message instanceof Error) { - cause = message; - message = cause.name + ": " + cause.message; - } - - if (Object.setPrototypeOf) { - err = new Error(message); - Object.setPrototypeOf(err, TemplateError.prototype); - } else { - err = this; - Object.defineProperty(err, 'message', { - enumerable: false, - writable: true, - value: message - }); - } - - Object.defineProperty(err, 'name', { - value: 'Template render error' - }); - - if (Error.captureStackTrace) { - Error.captureStackTrace(err, this.constructor); - } - - var getStack; - - if (cause) { - var stackDescriptor = Object.getOwnPropertyDescriptor(cause, 'stack'); - - getStack = stackDescriptor && (stackDescriptor.get || function () { - return stackDescriptor.value; - }); - - if (!getStack) { - getStack = function getStack() { - return cause.stack; - }; - } - } else { - var stack = new Error(message).stack; - - getStack = function getStack() { - return stack; - }; - } - - Object.defineProperty(err, 'stack', { - get: function get() { - return getStack.call(err); - } - }); - Object.defineProperty(err, 'cause', { - value: cause - }); - err.lineno = lineno; - err.colno = colno; - err.firstUpdate = true; - - err.Update = function Update(path) { - var msg = '(' + (path || 'unknown path') + ')'; // only show lineno + colno next to path of template - // where error occurred - - if (this.firstUpdate) { - if (this.lineno && this.colno) { - msg += " [Line " + this.lineno + ", Column " + this.colno + "]"; - } else if (this.lineno) { - msg += " [Line " + this.lineno + "]"; - } - } - - msg += '\n '; - - if (this.firstUpdate) { - msg += ' '; - } - - this.message = msg + (this.message || ''); - this.firstUpdate = false; - return this; - }; - - return err; -} - -if (Object.setPrototypeOf) { - Object.setPrototypeOf(TemplateError.prototype, Error.prototype); -} else { - TemplateError.prototype = Object.create(Error.prototype, { - constructor: { - value: TemplateError - } - }); -} - -exports.TemplateError = TemplateError; - -function escape(val) { - return val.replace(escapeRegex, lookupEscape); -} - -exports.escape = escape; - -function isFunction(obj) { - return ObjProto.toString.call(obj) === '[object Function]'; -} - -exports.isFunction = isFunction; - -function isArray(obj) { - return ObjProto.toString.call(obj) === '[object Array]'; -} - -exports.isArray = isArray; - -function isString(obj) { - return ObjProto.toString.call(obj) === '[object String]'; -} - -exports.isString = isString; - -function isObject(obj) { - return ObjProto.toString.call(obj) === '[object Object]'; -} - -exports.isObject = isObject; -/** - * @param {string|number} attr - * @returns {(string|number)[]} - * @private - */ - -function _prepareAttributeParts(attr) { - if (!attr) { - return []; - } - - if (typeof attr === 'string') { - return attr.split('.'); - } - - return [attr]; -} -/** - * @param {string} attribute Attribute value. Dots allowed. - * @returns {function(Object): *} - */ - - -function getAttrGetter(attribute) { - var parts = _prepareAttributeParts(attribute); - - return function attrGetter(item) { - var _item = item; - - for (var i = 0; i < parts.length; i++) { - var part = parts[i]; // If item is not an object, and we still got parts to handle, it means - // that something goes wrong. Just roll out to undefined in that case. - - if (hasOwnProp(_item, part)) { - _item = _item[part]; - } else { - return undefined; - } - } - - return _item; - }; -} - -function groupBy(obj, val, throwOnUndefined) { - var result = {}; - var iterator = isFunction(val) ? val : getAttrGetter(val); - - for (var i = 0; i < obj.length; i++) { - var value = obj[i]; - var key = iterator(value, i); - - if (key === undefined && throwOnUndefined === true) { - throw new TypeError("groupby: attribute \"" + val + "\" resolved to undefined"); - } - - (result[key] || (result[key] = [])).push(value); - } - - return result; -} - -exports.groupBy = groupBy; - -function toArray(obj) { - return Array.prototype.slice.call(obj); -} - -exports.toArray = toArray; - -function without(array) { - var result = []; - - if (!array) { - return result; - } - - var length = array.length; - var contains = toArray(arguments).slice(1); - var index = -1; - - while (++index < length) { - if (indexOf(contains, array[index]) === -1) { - result.push(array[index]); - } - } - - return result; -} - -exports.without = without; - -function repeat(char_, n) { - var str = ''; - - for (var i = 0; i < n; i++) { - str += char_; - } - - return str; -} - -exports.repeat = repeat; - -function each(obj, func, context) { - if (obj == null) { - return; - } - - if (ArrayProto.forEach && obj.forEach === ArrayProto.forEach) { - obj.forEach(func, context); - } else if (obj.length === +obj.length) { - for (var i = 0, l = obj.length; i < l; i++) { - func.call(context, obj[i], i, obj); - } - } -} - -exports.each = each; - -function map(obj, func) { - var results = []; - - if (obj == null) { - return results; - } - - if (ArrayProto.map && obj.map === ArrayProto.map) { - return obj.map(func); - } - - for (var i = 0; i < obj.length; i++) { - results[results.length] = func(obj[i], i); - } - - if (obj.length === +obj.length) { - results.length = obj.length; - } - - return results; -} - -exports.map = map; - -function asyncIter(arr, iter, cb) { - var i = -1; - - function next() { - i++; - - if (i < arr.length) { - iter(arr[i], i, next, cb); - } else { - cb(); - } - } - - next(); -} - -exports.asyncIter = asyncIter; - -function asyncFor(obj, iter, cb) { - var keys = keys_(obj || {}); - var len = keys.length; - var i = -1; - - function next() { - i++; - var k = keys[i]; - - if (i < len) { - iter(k, obj[k], i, len, next); - } else { - cb(); - } - } - - next(); -} - -exports.asyncFor = asyncFor; - -function indexOf(arr, searchElement, fromIndex) { - return Array.prototype.indexOf.call(arr || [], searchElement, fromIndex); -} - -exports.indexOf = indexOf; - -function keys_(obj) { - /* eslint-disable no-restricted-syntax */ - var arr = []; - - for (var k in obj) { - if (hasOwnProp(obj, k)) { - arr.push(k); - } - } - - return arr; -} - -exports.keys = keys_; - -function _entries(obj) { - return keys_(obj).map(function (k) { - return [k, obj[k]]; - }); -} - -exports._entries = _entries; - -function _values(obj) { - return keys_(obj).map(function (k) { - return obj[k]; - }); -} - -exports._values = _values; - -function extend(obj1, obj2) { - obj1 = obj1 || {}; - keys_(obj2).forEach(function (k) { - obj1[k] = obj2[k]; - }); - return obj1; -} - -exports._assign = exports.extend = extend; - -function inOperator(key, val) { - if (isArray(val) || isString(val)) { - return val.indexOf(key) !== -1; - } else if (isObject(val)) { - return key in val; - } - - throw new Error('Cannot use "in" operator to search for "' + key + '" in unexpected types.'); -} - -exports.inOperator = inOperator; - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - // A simple class system, more documentation to come - -function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } - -function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } - -function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } - -var EventEmitter = __webpack_require__(16); - -var lib = __webpack_require__(0); - -function parentWrap(parent, prop) { - if (typeof parent !== 'function' || typeof prop !== 'function') { - return prop; - } - - return function wrap() { - // Save the current parent method - var tmp = this.parent; // Set parent to the previous method, call, and restore - - this.parent = parent; - var res = prop.apply(this, arguments); - this.parent = tmp; - return res; - }; -} - -function extendClass(cls, name, props) { - props = props || {}; - lib.keys(props).forEach(function (k) { - props[k] = parentWrap(cls.prototype[k], props[k]); - }); - - var subclass = - /*#__PURE__*/ - function (_cls) { - _inheritsLoose(subclass, _cls); - - function subclass() { - return _cls.apply(this, arguments) || this; - } - - _createClass(subclass, [{ - key: "typename", - get: function get() { - return name; - } - }]); - - return subclass; - }(cls); - - lib._assign(subclass.prototype, props); - - return subclass; -} - -var Obj = -/*#__PURE__*/ -function () { - function Obj() { - // Unfortunately necessary for backwards compatibility - this.init.apply(this, arguments); - } - - var _proto = Obj.prototype; - - _proto.init = function init() {}; - - Obj.extend = function extend(name, props) { - if (typeof name === 'object') { - props = name; - name = 'anonymous'; - } - - return extendClass(this, name, props); - }; - - _createClass(Obj, [{ - key: "typename", - get: function get() { - return this.constructor.name; - } - }]); - - return Obj; -}(); - -var EmitterObj = -/*#__PURE__*/ -function (_EventEmitter) { - _inheritsLoose(EmitterObj, _EventEmitter); - - function EmitterObj() { - var _this2; - - var _this; - - _this = _EventEmitter.call(this) || this; // Unfortunately necessary for backwards compatibility - - (_this2 = _this).init.apply(_this2, arguments); - - return _this; - } - - var _proto2 = EmitterObj.prototype; - - _proto2.init = function init() {}; - - EmitterObj.extend = function extend(name, props) { - if (typeof name === 'object') { - props = name; - name = 'anonymous'; - } - - return extendClass(this, name, props); - }; - - _createClass(EmitterObj, [{ - key: "typename", - get: function get() { - return this.constructor.name; - } - }]); - - return EmitterObj; -}(EventEmitter); - -module.exports = { - Obj: Obj, - EmitterObj: EmitterObj -}; - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var lib = __webpack_require__(0); - -var arrayFrom = Array.from; -var supportsIterators = typeof Symbol === 'function' && Symbol.iterator && typeof arrayFrom === 'function'; // Frames keep track of scoping both at compile-time and run-time so -// we know how to access variables. Block tags can introduce special -// variables, for example. - -var Frame = -/*#__PURE__*/ -function () { - function Frame(parent, isolateWrites) { - this.variables = {}; - this.parent = parent; - this.topLevel = false; // if this is true, writes (set) should never propagate upwards past - // this frame to its parent (though reads may). - - this.isolateWrites = isolateWrites; - } - - var _proto = Frame.prototype; - - _proto.set = function set(name, val, resolveUp) { - // Allow variables with dots by automatically creating the - // nested structure - var parts = name.split('.'); - var obj = this.variables; - var frame = this; - - if (resolveUp) { - if (frame = this.resolve(parts[0], true)) { - frame.set(name, val); - return; - } - } - - for (var i = 0; i < parts.length - 1; i++) { - var id = parts[i]; - - if (!obj[id]) { - obj[id] = {}; - } - - obj = obj[id]; - } - - obj[parts[parts.length - 1]] = val; - }; - - _proto.get = function get(name) { - var val = this.variables[name]; - - if (val !== undefined) { - return val; - } - - return null; - }; - - _proto.lookup = function lookup(name) { - var p = this.parent; - var val = this.variables[name]; - - if (val !== undefined) { - return val; - } - - return p && p.lookup(name); - }; - - _proto.resolve = function resolve(name, forWrite) { - var p = forWrite && this.isolateWrites ? undefined : this.parent; - var val = this.variables[name]; - - if (val !== undefined) { - return this; - } - - return p && p.resolve(name); - }; - - _proto.push = function push(isolateWrites) { - return new Frame(this, isolateWrites); - }; - - _proto.pop = function pop() { - return this.parent; - }; - - return Frame; -}(); - -function makeMacro(argNames, kwargNames, func) { - var _this = this; - - return function () { - for (var _len = arguments.length, macroArgs = new Array(_len), _key = 0; _key < _len; _key++) { - macroArgs[_key] = arguments[_key]; - } - - var argCount = numArgs(macroArgs); - var args; - var kwargs = getKeywordArgs(macroArgs); - - if (argCount > argNames.length) { - args = macroArgs.slice(0, argNames.length); // Positional arguments that should be passed in as - // keyword arguments (essentially default values) - - macroArgs.slice(args.length, argCount).forEach(function (val, i) { - if (i < kwargNames.length) { - kwargs[kwargNames[i]] = val; - } - }); - args.push(kwargs); - } else if (argCount < argNames.length) { - args = macroArgs.slice(0, argCount); - - for (var i = argCount; i < argNames.length; i++) { - var arg = argNames[i]; // Keyword arguments that should be passed as - // positional arguments, i.e. the caller explicitly - // used the name of a positional arg - - args.push(kwargs[arg]); - delete kwargs[arg]; - } - - args.push(kwargs); - } else { - args = macroArgs; - } - - return func.apply(_this, args); - }; -} - -function makeKeywordArgs(obj) { - obj.__keywords = true; - return obj; -} - -function isKeywordArgs(obj) { - return obj && Object.prototype.hasOwnProperty.call(obj, '__keywords'); -} - -function getKeywordArgs(args) { - var len = args.length; - - if (len) { - var lastArg = args[len - 1]; - - if (isKeywordArgs(lastArg)) { - return lastArg; - } - } - - return {}; -} - -function numArgs(args) { - var len = args.length; - - if (len === 0) { - return 0; - } - - var lastArg = args[len - 1]; - - if (isKeywordArgs(lastArg)) { - return len - 1; - } else { - return len; - } -} // A SafeString object indicates that the string should not be -// autoescaped. This happens magically because autoescaping only -// occurs on primitive string objects. - - -function SafeString(val) { - if (typeof val !== 'string') { - return val; - } - - this.val = val; - this.length = val.length; -} - -SafeString.prototype = Object.create(String.prototype, { - length: { - writable: true, - configurable: true, - value: 0 - } -}); - -SafeString.prototype.valueOf = function valueOf() { - return this.val; -}; - -SafeString.prototype.toString = function toString() { - return this.val; -}; - -function copySafeness(dest, target) { - if (dest instanceof SafeString) { - return new SafeString(target); - } - - return target.toString(); -} - -function markSafe(val) { - var type = typeof val; - - if (type === 'string') { - return new SafeString(val); - } else if (type !== 'function') { - return val; - } else { - return function wrapSafe(args) { - var ret = val.apply(this, arguments); - - if (typeof ret === 'string') { - return new SafeString(ret); - } - - return ret; - }; - } -} - -function suppressValue(val, autoescape) { - val = val !== undefined && val !== null ? val : ''; - - if (autoescape && !(val instanceof SafeString)) { - val = lib.escape(val.toString()); - } - - return val; -} - -function ensureDefined(val, lineno, colno) { - if (val === null || val === undefined) { - throw new lib.TemplateError('attempted to output null or undefined value', lineno + 1, colno + 1); - } - - return val; -} - -function memberLookup(obj, val) { - if (obj === undefined || obj === null) { - return undefined; - } - - if (typeof obj[val] === 'function') { - return function () { - for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { - args[_key2] = arguments[_key2]; - } - - return obj[val].apply(obj, args); - }; - } - - return obj[val]; -} - -function callWrap(obj, name, context, args) { - if (!obj) { - throw new Error('Unable to call `' + name + '`, which is undefined or falsey'); - } else if (typeof obj !== 'function') { - throw new Error('Unable to call `' + name + '`, which is not a function'); - } - - return obj.apply(context, args); -} - -function contextOrFrameLookup(context, frame, name) { - var val = frame.lookup(name); - return val !== undefined ? val : context.lookup(name); -} - -function handleError(error, lineno, colno) { - if (error.lineno) { - return error; - } else { - return new lib.TemplateError(error, lineno, colno); - } -} - -function asyncEach(arr, dimen, iter, cb) { - if (lib.isArray(arr)) { - var len = arr.length; - lib.asyncIter(arr, function iterCallback(item, i, next) { - switch (dimen) { - case 1: - iter(item, i, len, next); - break; - - case 2: - iter(item[0], item[1], i, len, next); - break; - - case 3: - iter(item[0], item[1], item[2], i, len, next); - break; - - default: - item.push(i, len, next); - iter.apply(this, item); - } - }, cb); - } else { - lib.asyncFor(arr, function iterCallback(key, val, i, len, next) { - iter(key, val, i, len, next); - }, cb); - } -} - -function asyncAll(arr, dimen, func, cb) { - var finished = 0; - var len; - var outputArr; - - function done(i, output) { - finished++; - outputArr[i] = output; - - if (finished === len) { - cb(null, outputArr.join('')); - } - } - - if (lib.isArray(arr)) { - len = arr.length; - outputArr = new Array(len); - - if (len === 0) { - cb(null, ''); - } else { - for (var i = 0; i < arr.length; i++) { - var item = arr[i]; - - switch (dimen) { - case 1: - func(item, i, len, done); - break; - - case 2: - func(item[0], item[1], i, len, done); - break; - - case 3: - func(item[0], item[1], item[2], i, len, done); - break; - - default: - item.push(i, len, done); - func.apply(this, item); - } - } - } - } else { - var keys = lib.keys(arr || {}); - len = keys.length; - outputArr = new Array(len); - - if (len === 0) { - cb(null, ''); - } else { - for (var _i = 0; _i < keys.length; _i++) { - var k = keys[_i]; - func(k, arr[k], _i, len, done); - } - } - } -} - -function fromIterator(arr) { - if (typeof arr !== 'object' || arr === null || lib.isArray(arr)) { - return arr; - } else if (supportsIterators && Symbol.iterator in arr) { - return arrayFrom(arr); - } else { - return arr; - } -} - -module.exports = { - Frame: Frame, - makeMacro: makeMacro, - makeKeywordArgs: makeKeywordArgs, - numArgs: numArgs, - suppressValue: suppressValue, - ensureDefined: ensureDefined, - memberLookup: memberLookup, - contextOrFrameLookup: contextOrFrameLookup, - callWrap: callWrap, - handleError: handleError, - isArray: lib.isArray, - keys: lib.keys, - SafeString: SafeString, - copySafeness: copySafeness, - markSafe: markSafe, - asyncEach: asyncEach, - asyncAll: asyncAll, - inOperator: lib.inOperator, - fromIterator: fromIterator -}; - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } - -function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } - -function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } - -var _require = __webpack_require__(1), - Obj = _require.Obj; - -function traverseAndCheck(obj, type, results) { - if (obj instanceof type) { - results.push(obj); - } - - if (obj instanceof Node) { - obj.findAll(type, results); - } -} - -var Node = -/*#__PURE__*/ -function (_Obj) { - _inheritsLoose(Node, _Obj); - - function Node() { - return _Obj.apply(this, arguments) || this; - } - - var _proto = Node.prototype; - - _proto.init = function init(lineno, colno) { - var _this = this, - _arguments = arguments; - - for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { - args[_key - 2] = arguments[_key]; - } - - this.lineno = lineno; - this.colno = colno; - this.fields.forEach(function (field, i) { - // The first two args are line/col numbers, so offset by 2 - var val = _arguments[i + 2]; // Fields should never be undefined, but null. It makes - // testing easier to normalize values. - - if (val === undefined) { - val = null; - } - - _this[field] = val; - }); - }; - - _proto.findAll = function findAll(type, results) { - var _this2 = this; - - results = results || []; - - if (this instanceof NodeList) { - this.children.forEach(function (child) { - return traverseAndCheck(child, type, results); - }); - } else { - this.fields.forEach(function (field) { - return traverseAndCheck(_this2[field], type, results); - }); - } - - return results; - }; - - _proto.iterFields = function iterFields(func) { - var _this3 = this; - - this.fields.forEach(function (field) { - func(_this3[field], field); - }); - }; - - return Node; -}(Obj); // Abstract nodes - - -var Value = -/*#__PURE__*/ -function (_Node) { - _inheritsLoose(Value, _Node); - - function Value() { - return _Node.apply(this, arguments) || this; - } - - _createClass(Value, [{ - key: "typename", - get: function get() { - return 'Value'; - } - }, { - key: "fields", - get: function get() { - return ['value']; - } - }]); - - return Value; -}(Node); // Concrete nodes - - -var NodeList = -/*#__PURE__*/ -function (_Node2) { - _inheritsLoose(NodeList, _Node2); - - function NodeList() { - return _Node2.apply(this, arguments) || this; - } - - var _proto2 = NodeList.prototype; - - _proto2.init = function init(lineno, colno, nodes) { - _Node2.prototype.init.call(this, lineno, colno, nodes || []); - }; - - _proto2.addChild = function addChild(node) { - this.children.push(node); - }; - - _createClass(NodeList, [{ - key: "typename", - get: function get() { - return 'NodeList'; - } - }, { - key: "fields", - get: function get() { - return ['children']; - } - }]); - - return NodeList; -}(Node); - -var Root = NodeList.extend('Root'); -var Literal = Value.extend('Literal'); -var Symbol = Value.extend('Symbol'); -var Group = NodeList.extend('Group'); -var ArrayNode = NodeList.extend('Array'); -var Pair = Node.extend('Pair', { - fields: ['key', 'value'] -}); -var Dict = NodeList.extend('Dict'); -var LookupVal = Node.extend('LookupVal', { - fields: ['target', 'val'] -}); -var If = Node.extend('If', { - fields: ['cond', 'body', 'else_'] -}); -var IfAsync = If.extend('IfAsync'); -var InlineIf = Node.extend('InlineIf', { - fields: ['cond', 'body', 'else_'] -}); -var For = Node.extend('For', { - fields: ['arr', 'name', 'body', 'else_'] -}); -var AsyncEach = For.extend('AsyncEach'); -var AsyncAll = For.extend('AsyncAll'); -var Macro = Node.extend('Macro', { - fields: ['name', 'args', 'body'] -}); -var Caller = Macro.extend('Caller'); -var Import = Node.extend('Import', { - fields: ['template', 'target', 'withContext'] -}); - -var FromImport = -/*#__PURE__*/ -function (_Node3) { - _inheritsLoose(FromImport, _Node3); - - function FromImport() { - return _Node3.apply(this, arguments) || this; - } - - var _proto3 = FromImport.prototype; - - _proto3.init = function init(lineno, colno, template, names, withContext) { - _Node3.prototype.init.call(this, lineno, colno, template, names || new NodeList(), withContext); - }; - - _createClass(FromImport, [{ - key: "typename", - get: function get() { - return 'FromImport'; - } - }, { - key: "fields", - get: function get() { - return ['template', 'names', 'withContext']; - } - }]); - - return FromImport; -}(Node); - -var FunCall = Node.extend('FunCall', { - fields: ['name', 'args'] -}); -var Filter = FunCall.extend('Filter'); -var FilterAsync = Filter.extend('FilterAsync', { - fields: ['name', 'args', 'symbol'] -}); -var KeywordArgs = Dict.extend('KeywordArgs'); -var Block = Node.extend('Block', { - fields: ['name', 'body'] -}); -var Super = Node.extend('Super', { - fields: ['blockName', 'symbol'] -}); -var TemplateRef = Node.extend('TemplateRef', { - fields: ['template'] -}); -var Extends = TemplateRef.extend('Extends'); -var Include = Node.extend('Include', { - fields: ['template', 'ignoreMissing'] -}); -var Set = Node.extend('Set', { - fields: ['targets', 'value'] -}); -var Switch = Node.extend('Switch', { - fields: ['expr', 'cases', 'default'] -}); -var Case = Node.extend('Case', { - fields: ['cond', 'body'] -}); -var Output = NodeList.extend('Output'); -var Capture = Node.extend('Capture', { - fields: ['body'] -}); -var TemplateData = Literal.extend('TemplateData'); -var UnaryOp = Node.extend('UnaryOp', { - fields: ['target'] -}); -var BinOp = Node.extend('BinOp', { - fields: ['left', 'right'] -}); -var In = BinOp.extend('In'); -var Is = BinOp.extend('Is'); -var Or = BinOp.extend('Or'); -var And = BinOp.extend('And'); -var Not = UnaryOp.extend('Not'); -var Add = BinOp.extend('Add'); -var Concat = BinOp.extend('Concat'); -var Sub = BinOp.extend('Sub'); -var Mul = BinOp.extend('Mul'); -var Div = BinOp.extend('Div'); -var FloorDiv = BinOp.extend('FloorDiv'); -var Mod = BinOp.extend('Mod'); -var Pow = BinOp.extend('Pow'); -var Neg = UnaryOp.extend('Neg'); -var Pos = UnaryOp.extend('Pos'); -var Compare = Node.extend('Compare', { - fields: ['expr', 'ops'] -}); -var CompareOperand = Node.extend('CompareOperand', { - fields: ['expr', 'type'] -}); -var CallExtension = Node.extend('CallExtension', { - init: function init(ext, prop, args, contentArgs) { - this.parent(); - this.extName = ext.__name || ext; - this.prop = prop; - this.args = args || new NodeList(); - this.contentArgs = contentArgs || []; - this.autoescape = ext.autoescape; - }, - fields: ['extName', 'prop', 'args', 'contentArgs'] -}); -var CallExtensionAsync = CallExtension.extend('CallExtensionAsync'); // This is hacky, but this is just a debugging function anyway - -function print(str, indent, inline) { - var lines = str.split('\n'); - lines.forEach(function (line, i) { - if (line && (inline && i > 0 || !inline)) { - process.stdout.write(' '.repeat(indent)); - } - - var nl = i === lines.length - 1 ? '' : '\n'; - process.stdout.write("" + line + nl); - }); -} // Print the AST in a nicely formatted tree format for debuggin - - -function printNodes(node, indent) { - indent = indent || 0; - print(node.typename + ': ', indent); - - if (node instanceof NodeList) { - print('\n'); - node.children.forEach(function (n) { - printNodes(n, indent + 2); - }); - } else if (node instanceof CallExtension) { - print(node.extName + "." + node.prop + "\n"); - - if (node.args) { - printNodes(node.args, indent + 2); - } - - if (node.contentArgs) { - node.contentArgs.forEach(function (n) { - printNodes(n, indent + 2); - }); - } - } else { - var nodes = []; - var props = null; - node.iterFields(function (val, fieldName) { - if (val instanceof Node) { - nodes.push([fieldName, val]); - } else { - props = props || {}; - props[fieldName] = val; - } - }); - - if (props) { - print(JSON.stringify(props, null, 2) + '\n', null, true); - } else { - print('\n'); - } - - nodes.forEach(function (_ref) { - var fieldName = _ref[0], - n = _ref[1]; - print("[" + fieldName + "] =>", indent + 2); - printNodes(n, indent + 4); - }); - } -} - -module.exports = { - Node: Node, - Root: Root, - NodeList: NodeList, - Value: Value, - Literal: Literal, - Symbol: Symbol, - Group: Group, - Array: ArrayNode, - Pair: Pair, - Dict: Dict, - Output: Output, - Capture: Capture, - TemplateData: TemplateData, - If: If, - IfAsync: IfAsync, - InlineIf: InlineIf, - For: For, - AsyncEach: AsyncEach, - AsyncAll: AsyncAll, - Macro: Macro, - Caller: Caller, - Import: Import, - FromImport: FromImport, - FunCall: FunCall, - Filter: Filter, - FilterAsync: FilterAsync, - KeywordArgs: KeywordArgs, - Block: Block, - Super: Super, - Extends: Extends, - Include: Include, - Set: Set, - Switch: Switch, - Case: Case, - LookupVal: LookupVal, - BinOp: BinOp, - In: In, - Is: Is, - Or: Or, - And: And, - Not: Not, - Add: Add, - Concat: Concat, - Sub: Sub, - Mul: Mul, - Div: Div, - FloorDiv: FloorDiv, - Mod: Mod, - Pow: Pow, - Neg: Neg, - Pos: Pos, - Compare: Compare, - CompareOperand: CompareOperand, - CallExtension: CallExtension, - CallExtensionAsync: CallExtensionAsync, - printNodes: printNodes -}; - -/***/ }), -/* 4 */ -/***/ (function(module, exports) { - - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } - -var parser = __webpack_require__(8); - -var transformer = __webpack_require__(17); - -var nodes = __webpack_require__(3); - -var _require = __webpack_require__(0), - TemplateError = _require.TemplateError; - -var _require2 = __webpack_require__(2), - Frame = _require2.Frame; - -var _require3 = __webpack_require__(1), - Obj = _require3.Obj; // These are all the same for now, but shouldn't be passed straight -// through - - -var compareOps = { - '==': '==', - '===': '===', - '!=': '!=', - '!==': '!==', - '<': '<', - '>': '>', - '<=': '<=', - '>=': '>=' -}; - -var Compiler = -/*#__PURE__*/ -function (_Obj) { - _inheritsLoose(Compiler, _Obj); - - function Compiler() { - return _Obj.apply(this, arguments) || this; - } - - var _proto = Compiler.prototype; - - _proto.init = function init(templateName, throwOnUndefined) { - this.templateName = templateName; - this.codebuf = []; - this.lastId = 0; - this.buffer = null; - this.bufferStack = []; - this._scopeClosers = ''; - this.inBlock = false; - this.throwOnUndefined = throwOnUndefined; - }; - - _proto.fail = function fail(msg, lineno, colno) { - if (lineno !== undefined) { - lineno += 1; - } - - if (colno !== undefined) { - colno += 1; - } - - throw new TemplateError(msg, lineno, colno); - }; - - _proto._pushBuffer = function _pushBuffer() { - var id = this._tmpid(); - - this.bufferStack.push(this.buffer); - this.buffer = id; - - this._emit("var " + this.buffer + " = \"\";"); - - return id; - }; - - _proto._popBuffer = function _popBuffer() { - this.buffer = this.bufferStack.pop(); - }; - - _proto._emit = function _emit(code) { - this.codebuf.push(code); - }; - - _proto._emitLine = function _emitLine(code) { - this._emit(code + '\n'); - }; - - _proto._emitLines = function _emitLines() { - var _this = this; - - for (var _len = arguments.length, lines = new Array(_len), _key = 0; _key < _len; _key++) { - lines[_key] = arguments[_key]; - } - - lines.forEach(function (line) { - return _this._emitLine(line); - }); - }; - - _proto._emitFuncBegin = function _emitFuncBegin(node, name) { - this.buffer = 'output'; - this._scopeClosers = ''; - - this._emitLine("function " + name + "(env, context, frame, runtime, cb) {"); - - this._emitLine("var lineno = " + node.lineno + ";"); - - this._emitLine("var colno = " + node.colno + ";"); - - this._emitLine("var " + this.buffer + " = \"\";"); - - this._emitLine('try {'); - }; - - _proto._emitFuncEnd = function _emitFuncEnd(noReturn) { - if (!noReturn) { - this._emitLine('cb(null, ' + this.buffer + ');'); - } - - this._closeScopeLevels(); - - this._emitLine('} catch (e) {'); - - this._emitLine(' cb(runtime.handleError(e, lineno, colno));'); - - this._emitLine('}'); - - this._emitLine('}'); - - this.buffer = null; - }; - - _proto._addScopeLevel = function _addScopeLevel() { - this._scopeClosers += '})'; - }; - - _proto._closeScopeLevels = function _closeScopeLevels() { - this._emitLine(this._scopeClosers + ';'); - - this._scopeClosers = ''; - }; - - _proto._withScopedSyntax = function _withScopedSyntax(func) { - var _scopeClosers = this._scopeClosers; - this._scopeClosers = ''; - func.call(this); - - this._closeScopeLevels(); - - this._scopeClosers = _scopeClosers; - }; - - _proto._makeCallback = function _makeCallback(res) { - var err = this._tmpid(); - - return 'function(' + err + (res ? ',' + res : '') + ') {\n' + 'if(' + err + ') { cb(' + err + '); return; }'; - }; - - _proto._tmpid = function _tmpid() { - this.lastId++; - return 't_' + this.lastId; - }; - - _proto._templateName = function _templateName() { - return this.templateName == null ? 'undefined' : JSON.stringify(this.templateName); - }; - - _proto._compileChildren = function _compileChildren(node, frame) { - var _this2 = this; - - node.children.forEach(function (child) { - _this2.compile(child, frame); - }); - }; - - _proto._compileAggregate = function _compileAggregate(node, frame, startChar, endChar) { - var _this3 = this; - - if (startChar) { - this._emit(startChar); - } - - node.children.forEach(function (child, i) { - if (i > 0) { - _this3._emit(','); - } - - _this3.compile(child, frame); - }); - - if (endChar) { - this._emit(endChar); - } - }; - - _proto._compileExpression = function _compileExpression(node, frame) { - // TODO: I'm not really sure if this type check is worth it or - // not. - this.assertType(node, nodes.Literal, nodes.Symbol, nodes.Group, nodes.Array, nodes.Dict, nodes.FunCall, nodes.Caller, nodes.Filter, nodes.LookupVal, nodes.Compare, nodes.InlineIf, nodes.In, nodes.Is, nodes.And, nodes.Or, nodes.Not, nodes.Add, nodes.Concat, nodes.Sub, nodes.Mul, nodes.Div, nodes.FloorDiv, nodes.Mod, nodes.Pow, nodes.Neg, nodes.Pos, nodes.Compare, nodes.NodeList); - this.compile(node, frame); - }; - - _proto.assertType = function assertType(node) { - for (var _len2 = arguments.length, types = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { - types[_key2 - 1] = arguments[_key2]; - } - - if (!types.some(function (t) { - return node instanceof t; - })) { - this.fail("assertType: invalid type: " + node.typename, node.lineno, node.colno); - } - }; - - _proto.compileCallExtension = function compileCallExtension(node, frame, async) { - var _this4 = this; - - var args = node.args; - var contentArgs = node.contentArgs; - var autoescape = typeof node.autoescape === 'boolean' ? node.autoescape : true; - - if (!async) { - this._emit(this.buffer + " += runtime.suppressValue("); - } - - this._emit("env.getExtension(\"" + node.extName + "\")[\"" + node.prop + "\"]("); - - this._emit('context'); - - if (args || contentArgs) { - this._emit(','); - } - - if (args) { - if (!(args instanceof nodes.NodeList)) { - this.fail('compileCallExtension: arguments must be a NodeList, ' + 'use `parser.parseSignature`'); - } - - args.children.forEach(function (arg, i) { - // Tag arguments are passed normally to the call. Note - // that keyword arguments are turned into a single js - // object as the last argument, if they exist. - _this4._compileExpression(arg, frame); - - if (i !== args.children.length - 1 || contentArgs.length) { - _this4._emit(','); - } - }); - } - - if (contentArgs.length) { - contentArgs.forEach(function (arg, i) { - if (i > 0) { - _this4._emit(','); - } - - if (arg) { - _this4._emitLine('function(cb) {'); - - _this4._emitLine('if(!cb) { cb = function(err) { if(err) { throw err; }}}'); - - var id = _this4._pushBuffer(); - - _this4._withScopedSyntax(function () { - _this4.compile(arg, frame); - - _this4._emitLine("cb(null, " + id + ");"); - }); - - _this4._popBuffer(); - - _this4._emitLine("return " + id + ";"); - - _this4._emitLine('}'); - } else { - _this4._emit('null'); - } - }); - } - - if (async) { - var res = this._tmpid(); - - this._emitLine(', ' + this._makeCallback(res)); - - this._emitLine(this.buffer + " += runtime.suppressValue(" + res + ", " + autoescape + " && env.opts.autoescape);"); - - this._addScopeLevel(); - } else { - this._emit(')'); - - this._emit(", " + autoescape + " && env.opts.autoescape);\n"); - } - }; - - _proto.compileCallExtensionAsync = function compileCallExtensionAsync(node, frame) { - this.compileCallExtension(node, frame, true); - }; - - _proto.compileNodeList = function compileNodeList(node, frame) { - this._compileChildren(node, frame); - }; - - _proto.compileLiteral = function compileLiteral(node) { - if (typeof node.value === 'string') { - var val = node.value.replace(/\\/g, '\\\\'); - val = val.replace(/"/g, '\\"'); - val = val.replace(/\n/g, '\\n'); - val = val.replace(/\r/g, '\\r'); - val = val.replace(/\t/g, '\\t'); - val = val.replace(/\u2028/g, "\\u2028"); - - this._emit("\"" + val + "\""); - } else if (node.value === null) { - this._emit('null'); - } else { - this._emit(node.value.toString()); - } - }; - - _proto.compileSymbol = function compileSymbol(node, frame) { - var name = node.value; - var v = frame.lookup(name); - - if (v) { - this._emit(v); - } else { - this._emit('runtime.contextOrFrameLookup(' + 'context, frame, "' + name + '")'); - } - }; - - _proto.compileGroup = function compileGroup(node, frame) { - this._compileAggregate(node, frame, '(', ')'); - }; - - _proto.compileArray = function compileArray(node, frame) { - this._compileAggregate(node, frame, '[', ']'); - }; - - _proto.compileDict = function compileDict(node, frame) { - this._compileAggregate(node, frame, '{', '}'); - }; - - _proto.compilePair = function compilePair(node, frame) { - var key = node.key; - var val = node.value; - - if (key instanceof nodes.Symbol) { - key = new nodes.Literal(key.lineno, key.colno, key.value); - } else if (!(key instanceof nodes.Literal && typeof key.value === 'string')) { - this.fail('compilePair: Dict keys must be strings or names', key.lineno, key.colno); - } - - this.compile(key, frame); - - this._emit(': '); - - this._compileExpression(val, frame); - }; - - _proto.compileInlineIf = function compileInlineIf(node, frame) { - this._emit('('); - - this.compile(node.cond, frame); - - this._emit('?'); - - this.compile(node.body, frame); - - this._emit(':'); - - if (node.else_ !== null) { - this.compile(node.else_, frame); - } else { - this._emit('""'); - } - - this._emit(')'); - }; - - _proto.compileIn = function compileIn(node, frame) { - this._emit('runtime.inOperator('); - - this.compile(node.left, frame); - - this._emit(','); - - this.compile(node.right, frame); - - this._emit(')'); - }; - - _proto.compileIs = function compileIs(node, frame) { - // first, we need to try to get the name of the test function, if it's a - // callable (i.e., has args) and not a symbol. - var right = node.right.name ? node.right.name.value // otherwise go with the symbol value - : node.right.value; - - this._emit('env.getTest("' + right + '").call(context, '); - - this.compile(node.left, frame); // compile the arguments for the callable if they exist - - if (node.right.args) { - this._emit(','); - - this.compile(node.right.args, frame); - } - - this._emit(') === true'); - }; - - _proto._binOpEmitter = function _binOpEmitter(node, frame, str) { - this.compile(node.left, frame); - - this._emit(str); - - this.compile(node.right, frame); - }; // ensure concatenation instead of addition - // by adding empty string in between - - - _proto.compileOr = function compileOr(node, frame) { - return this._binOpEmitter(node, frame, ' || '); - }; - - _proto.compileAnd = function compileAnd(node, frame) { - return this._binOpEmitter(node, frame, ' && '); - }; - - _proto.compileAdd = function compileAdd(node, frame) { - return this._binOpEmitter(node, frame, ' + '); - }; - - _proto.compileConcat = function compileConcat(node, frame) { - return this._binOpEmitter(node, frame, ' + "" + '); - }; - - _proto.compileSub = function compileSub(node, frame) { - return this._binOpEmitter(node, frame, ' - '); - }; - - _proto.compileMul = function compileMul(node, frame) { - return this._binOpEmitter(node, frame, ' * '); - }; - - _proto.compileDiv = function compileDiv(node, frame) { - return this._binOpEmitter(node, frame, ' / '); - }; - - _proto.compileMod = function compileMod(node, frame) { - return this._binOpEmitter(node, frame, ' % '); - }; - - _proto.compileNot = function compileNot(node, frame) { - this._emit('!'); - - this.compile(node.target, frame); - }; - - _proto.compileFloorDiv = function compileFloorDiv(node, frame) { - this._emit('Math.floor('); - - this.compile(node.left, frame); - - this._emit(' / '); - - this.compile(node.right, frame); - - this._emit(')'); - }; - - _proto.compilePow = function compilePow(node, frame) { - this._emit('Math.pow('); - - this.compile(node.left, frame); - - this._emit(', '); - - this.compile(node.right, frame); - - this._emit(')'); - }; - - _proto.compileNeg = function compileNeg(node, frame) { - this._emit('-'); - - this.compile(node.target, frame); - }; - - _proto.compilePos = function compilePos(node, frame) { - this._emit('+'); - - this.compile(node.target, frame); - }; - - _proto.compileCompare = function compileCompare(node, frame) { - var _this5 = this; - - this.compile(node.expr, frame); - node.ops.forEach(function (op) { - _this5._emit(" " + compareOps[op.type] + " "); - - _this5.compile(op.expr, frame); - }); - }; - - _proto.compileLookupVal = function compileLookupVal(node, frame) { - this._emit('runtime.memberLookup(('); - - this._compileExpression(node.target, frame); - - this._emit('),'); - - this._compileExpression(node.val, frame); - - this._emit(')'); - }; - - _proto._getNodeName = function _getNodeName(node) { - switch (node.typename) { - case 'Symbol': - return node.value; - - case 'FunCall': - return 'the return value of (' + this._getNodeName(node.name) + ')'; - - case 'LookupVal': - return this._getNodeName(node.target) + '["' + this._getNodeName(node.val) + '"]'; - - case 'Literal': - return node.value.toString(); - - default: - return '--expression--'; - } - }; - - _proto.compileFunCall = function compileFunCall(node, frame) { - // Keep track of line/col info at runtime by settings - // variables within an expression. An expression in javascript - // like (x, y, z) returns the last value, and x and y can be - // anything - this._emit('(lineno = ' + node.lineno + ', colno = ' + node.colno + ', '); - - this._emit('runtime.callWrap('); // Compile it as normal. - - - this._compileExpression(node.name, frame); // Output the name of what we're calling so we can get friendly errors - // if the lookup fails. - - - this._emit(', "' + this._getNodeName(node.name).replace(/"/g, '\\"') + '", context, '); - - this._compileAggregate(node.args, frame, '[', '])'); - - this._emit(')'); - }; - - _proto.compileFilter = function compileFilter(node, frame) { - var name = node.name; - this.assertType(name, nodes.Symbol); - - this._emit('env.getFilter("' + name.value + '").call(context, '); - - this._compileAggregate(node.args, frame); - - this._emit(')'); - }; - - _proto.compileFilterAsync = function compileFilterAsync(node, frame) { - var name = node.name; - var symbol = node.symbol.value; - this.assertType(name, nodes.Symbol); - frame.set(symbol, symbol); - - this._emit('env.getFilter("' + name.value + '").call(context, '); - - this._compileAggregate(node.args, frame); - - this._emitLine(', ' + this._makeCallback(symbol)); - - this._addScopeLevel(); - }; - - _proto.compileKeywordArgs = function compileKeywordArgs(node, frame) { - this._emit('runtime.makeKeywordArgs('); - - this.compileDict(node, frame); - - this._emit(')'); - }; - - _proto.compileSet = function compileSet(node, frame) { - var _this6 = this; - - var ids = []; // Lookup the variable names for each identifier and create - // new ones if necessary - - node.targets.forEach(function (target) { - var name = target.value; - var id = frame.lookup(name); - - if (id === null || id === undefined) { - id = _this6._tmpid(); // Note: This relies on js allowing scope across - // blocks, in case this is created inside an `if` - - _this6._emitLine('var ' + id + ';'); - } - - ids.push(id); - }); - - if (node.value) { - this._emit(ids.join(' = ') + ' = '); - - this._compileExpression(node.value, frame); - - this._emitLine(';'); - } else { - this._emit(ids.join(' = ') + ' = '); - - this.compile(node.body, frame); - - this._emitLine(';'); - } - - node.targets.forEach(function (target, i) { - var id = ids[i]; - var name = target.value; // We are running this for every var, but it's very - // uncommon to assign to multiple vars anyway - - _this6._emitLine("frame.set(\"" + name + "\", " + id + ", true);"); - - _this6._emitLine('if(frame.topLevel) {'); - - _this6._emitLine("context.setVariable(\"" + name + "\", " + id + ");"); - - _this6._emitLine('}'); - - if (name.charAt(0) !== '_') { - _this6._emitLine('if(frame.topLevel) {'); - - _this6._emitLine("context.addExport(\"" + name + "\", " + id + ");"); - - _this6._emitLine('}'); - } - }); - }; - - _proto.compileSwitch = function compileSwitch(node, frame) { - var _this7 = this; - - this._emit('switch ('); - - this.compile(node.expr, frame); - - this._emit(') {'); - - node.cases.forEach(function (c, i) { - _this7._emit('case '); - - _this7.compile(c.cond, frame); - - _this7._emit(': '); - - _this7.compile(c.body, frame); // preserve fall-throughs - - - if (c.body.children.length) { - _this7._emitLine('break;'); - } - }); - - if (node.default) { - this._emit('default:'); - - this.compile(node.default, frame); - } - - this._emit('}'); - }; - - _proto.compileIf = function compileIf(node, frame, async) { - var _this8 = this; - - this._emit('if('); - - this._compileExpression(node.cond, frame); - - this._emitLine(') {'); - - this._withScopedSyntax(function () { - _this8.compile(node.body, frame); - - if (async) { - _this8._emit('cb()'); - } - }); - - if (node.else_) { - this._emitLine('}\nelse {'); - - this._withScopedSyntax(function () { - _this8.compile(node.else_, frame); - - if (async) { - _this8._emit('cb()'); - } - }); - } else if (async) { - this._emitLine('}\nelse {'); - - this._emit('cb()'); - } - - this._emitLine('}'); - }; - - _proto.compileIfAsync = function compileIfAsync(node, frame) { - this._emit('(function(cb) {'); - - this.compileIf(node, frame, true); - - this._emit('})(' + this._makeCallback()); - - this._addScopeLevel(); - }; - - _proto._emitLoopBindings = function _emitLoopBindings(node, arr, i, len) { - var _this9 = this; - - var bindings = [{ - name: 'index', - val: i + " + 1" - }, { - name: 'index0', - val: i - }, { - name: 'revindex', - val: len + " - " + i - }, { - name: 'revindex0', - val: len + " - " + i + " - 1" - }, { - name: 'first', - val: i + " === 0" - }, { - name: 'last', - val: i + " === " + len + " - 1" - }, { - name: 'length', - val: len - }]; - bindings.forEach(function (b) { - _this9._emitLine("frame.set(\"loop." + b.name + "\", " + b.val + ");"); - }); - }; - - _proto.compileFor = function compileFor(node, frame) { - var _this10 = this; - - // Some of this code is ugly, but it keeps the generated code - // as fast as possible. ForAsync also shares some of this, but - // not much. - var i = this._tmpid(); - - var len = this._tmpid(); - - var arr = this._tmpid(); - - frame = frame.push(); - - this._emitLine('frame = frame.push();'); - - this._emit("var " + arr + " = "); - - this._compileExpression(node.arr, frame); - - this._emitLine(';'); - - this._emit("if(" + arr + ") {"); - - this._emitLine(arr + ' = runtime.fromIterator(' + arr + ');'); // If multiple names are passed, we need to bind them - // appropriately - - - if (node.name instanceof nodes.Array) { - this._emitLine("var " + i + ";"); // The object could be an arroy or object. Note that the - // body of the loop is duplicated for each condition, but - // we are optimizing for speed over size. - - - this._emitLine("if(runtime.isArray(" + arr + ")) {"); - - this._emitLine("var " + len + " = " + arr + ".length;"); - - this._emitLine("for(" + i + "=0; " + i + " < " + arr + ".length; " + i + "++) {"); // Bind each declared var - - - node.name.children.forEach(function (child, u) { - var tid = _this10._tmpid(); - - _this10._emitLine("var " + tid + " = " + arr + "[" + i + "][" + u + "];"); - - _this10._emitLine("frame.set(\"" + child + "\", " + arr + "[" + i + "][" + u + "]);"); - - frame.set(node.name.children[u].value, tid); - }); - - this._emitLoopBindings(node, arr, i, len); - - this._withScopedSyntax(function () { - _this10.compile(node.body, frame); - }); - - this._emitLine('}'); - - this._emitLine('} else {'); // Iterate over the key/values of an object - - - var _node$name$children = node.name.children, - key = _node$name$children[0], - val = _node$name$children[1]; - - var k = this._tmpid(); - - var v = this._tmpid(); - - frame.set(key.value, k); - frame.set(val.value, v); - - this._emitLine(i + " = -1;"); - - this._emitLine("var " + len + " = runtime.keys(" + arr + ").length;"); - - this._emitLine("for(var " + k + " in " + arr + ") {"); - - this._emitLine(i + "++;"); - - this._emitLine("var " + v + " = " + arr + "[" + k + "];"); - - this._emitLine("frame.set(\"" + key.value + "\", " + k + ");"); - - this._emitLine("frame.set(\"" + val.value + "\", " + v + ");"); - - this._emitLoopBindings(node, arr, i, len); - - this._withScopedSyntax(function () { - _this10.compile(node.body, frame); - }); - - this._emitLine('}'); - - this._emitLine('}'); - } else { - // Generate a typical array iteration - var _v = this._tmpid(); - - frame.set(node.name.value, _v); - - this._emitLine("var " + len + " = " + arr + ".length;"); - - this._emitLine("for(var " + i + "=0; " + i + " < " + arr + ".length; " + i + "++) {"); - - this._emitLine("var " + _v + " = " + arr + "[" + i + "];"); - - this._emitLine("frame.set(\"" + node.name.value + "\", " + _v + ");"); - - this._emitLoopBindings(node, arr, i, len); - - this._withScopedSyntax(function () { - _this10.compile(node.body, frame); - }); - - this._emitLine('}'); - } - - this._emitLine('}'); - - if (node.else_) { - this._emitLine('if (!' + len + ') {'); - - this.compile(node.else_, frame); - - this._emitLine('}'); - } - - this._emitLine('frame = frame.pop();'); - }; - - _proto._compileAsyncLoop = function _compileAsyncLoop(node, frame, parallel) { - var _this11 = this; - - // This shares some code with the For tag, but not enough to - // worry about. This iterates across an object asynchronously, - // but not in parallel. - var i = this._tmpid(); - - var len = this._tmpid(); - - var arr = this._tmpid(); - - var asyncMethod = parallel ? 'asyncAll' : 'asyncEach'; - frame = frame.push(); - - this._emitLine('frame = frame.push();'); - - this._emit('var ' + arr + ' = runtime.fromIterator('); - - this._compileExpression(node.arr, frame); - - this._emitLine(');'); - - if (node.name instanceof nodes.Array) { - var arrayLen = node.name.children.length; - - this._emit("runtime." + asyncMethod + "(" + arr + ", " + arrayLen + ", function("); - - node.name.children.forEach(function (name) { - _this11._emit(name.value + ","); - }); - - this._emit(i + ',' + len + ',next) {'); - - node.name.children.forEach(function (name) { - var id = name.value; - frame.set(id, id); - - _this11._emitLine("frame.set(\"" + id + "\", " + id + ");"); - }); - } else { - var id = node.name.value; - - this._emitLine("runtime." + asyncMethod + "(" + arr + ", 1, function(" + id + ", " + i + ", " + len + ",next) {"); - - this._emitLine('frame.set("' + id + '", ' + id + ');'); - - frame.set(id, id); - } - - this._emitLoopBindings(node, arr, i, len); - - this._withScopedSyntax(function () { - var buf; - - if (parallel) { - buf = _this11._pushBuffer(); - } - - _this11.compile(node.body, frame); - - _this11._emitLine('next(' + i + (buf ? ',' + buf : '') + ');'); - - if (parallel) { - _this11._popBuffer(); - } - }); - - var output = this._tmpid(); - - this._emitLine('}, ' + this._makeCallback(output)); - - this._addScopeLevel(); - - if (parallel) { - this._emitLine(this.buffer + ' += ' + output + ';'); - } - - if (node.else_) { - this._emitLine('if (!' + arr + '.length) {'); - - this.compile(node.else_, frame); - - this._emitLine('}'); - } - - this._emitLine('frame = frame.pop();'); - }; - - _proto.compileAsyncEach = function compileAsyncEach(node, frame) { - this._compileAsyncLoop(node, frame); - }; - - _proto.compileAsyncAll = function compileAsyncAll(node, frame) { - this._compileAsyncLoop(node, frame, true); - }; - - _proto._compileMacro = function _compileMacro(node, frame) { - var _this12 = this; - - var args = []; - var kwargs = null; - - var funcId = 'macro_' + this._tmpid(); - - var keepFrame = frame !== undefined; // Type check the definition of the args - - node.args.children.forEach(function (arg, i) { - if (i === node.args.children.length - 1 && arg instanceof nodes.Dict) { - kwargs = arg; - } else { - _this12.assertType(arg, nodes.Symbol); - - args.push(arg); - } - }); - var realNames = args.map(function (n) { - return "l_" + n.value; - }).concat(['kwargs']); // Quoted argument names - - var argNames = args.map(function (n) { - return "\"" + n.value + "\""; - }); - var kwargNames = (kwargs && kwargs.children || []).map(function (n) { - return "\"" + n.key.value + "\""; - }); // We pass a function to makeMacro which destructures the - // arguments so support setting positional args with keywords - // args and passing keyword args as positional args - // (essentially default values). See runtime.js. - - var currFrame; - - if (keepFrame) { - currFrame = frame.push(true); - } else { - currFrame = new Frame(); - } - - this._emitLines("var " + funcId + " = runtime.makeMacro(", "[" + argNames.join(', ') + "], ", "[" + kwargNames.join(', ') + "], ", "function (" + realNames.join(', ') + ") {", 'var callerFrame = frame;', 'frame = ' + (keepFrame ? 'frame.push(true);' : 'new runtime.Frame();'), 'kwargs = kwargs || {};', 'if (Object.prototype.hasOwnProperty.call(kwargs, "caller")) {', 'frame.set("caller", kwargs.caller); }'); // Expose the arguments to the template. Don't need to use - // random names because the function - // will create a new run-time scope for us - - - args.forEach(function (arg) { - _this12._emitLine("frame.set(\"" + arg.value + "\", l_" + arg.value + ");"); - - currFrame.set(arg.value, "l_" + arg.value); - }); // Expose the keyword arguments - - if (kwargs) { - kwargs.children.forEach(function (pair) { - var name = pair.key.value; - - _this12._emit("frame.set(\"" + name + "\", "); - - _this12._emit("Object.prototype.hasOwnProperty.call(kwargs, \"" + name + "\")"); - - _this12._emit(" ? kwargs[\"" + name + "\"] : "); - - _this12._compileExpression(pair.value, currFrame); - - _this12._emit(');'); - }); - } - - var bufferId = this._pushBuffer(); - - this._withScopedSyntax(function () { - _this12.compile(node.body, currFrame); - }); - - this._emitLine('frame = ' + (keepFrame ? 'frame.pop();' : 'callerFrame;')); - - this._emitLine("return new runtime.SafeString(" + bufferId + ");"); - - this._emitLine('});'); - - this._popBuffer(); - - return funcId; - }; - - _proto.compileMacro = function compileMacro(node, frame) { - var funcId = this._compileMacro(node); // Expose the macro to the templates - - - var name = node.name.value; - frame.set(name, funcId); - - if (frame.parent) { - this._emitLine("frame.set(\"" + name + "\", " + funcId + ");"); - } else { - if (node.name.value.charAt(0) !== '_') { - this._emitLine("context.addExport(\"" + name + "\");"); - } - - this._emitLine("context.setVariable(\"" + name + "\", " + funcId + ");"); - } - }; - - _proto.compileCaller = function compileCaller(node, frame) { - // basically an anonymous "macro expression" - this._emit('(function (){'); - - var funcId = this._compileMacro(node, frame); - - this._emit("return " + funcId + ";})()"); - }; - - _proto._compileGetTemplate = function _compileGetTemplate(node, frame, eagerCompile, ignoreMissing) { - var parentTemplateId = this._tmpid(); - - var parentName = this._templateName(); - - var cb = this._makeCallback(parentTemplateId); - - var eagerCompileArg = eagerCompile ? 'true' : 'false'; - var ignoreMissingArg = ignoreMissing ? 'true' : 'false'; - - this._emit('env.getTemplate('); - - this._compileExpression(node.template, frame); - - this._emitLine(", " + eagerCompileArg + ", " + parentName + ", " + ignoreMissingArg + ", " + cb); - - return parentTemplateId; - }; - - _proto.compileImport = function compileImport(node, frame) { - var target = node.target.value; - - var id = this._compileGetTemplate(node, frame, false, false); - - this._addScopeLevel(); - - this._emitLine(id + '.getExported(' + (node.withContext ? 'context.getVariables(), frame, ' : '') + this._makeCallback(id)); - - this._addScopeLevel(); - - frame.set(target, id); - - if (frame.parent) { - this._emitLine("frame.set(\"" + target + "\", " + id + ");"); - } else { - this._emitLine("context.setVariable(\"" + target + "\", " + id + ");"); - } - }; - - _proto.compileFromImport = function compileFromImport(node, frame) { - var _this13 = this; - - var importedId = this._compileGetTemplate(node, frame, false, false); - - this._addScopeLevel(); - - this._emitLine(importedId + '.getExported(' + (node.withContext ? 'context.getVariables(), frame, ' : '') + this._makeCallback(importedId)); - - this._addScopeLevel(); - - node.names.children.forEach(function (nameNode) { - var name; - var alias; - - var id = _this13._tmpid(); - - if (nameNode instanceof nodes.Pair) { - name = nameNode.key.value; - alias = nameNode.value.value; - } else { - name = nameNode.value; - alias = name; - } - - _this13._emitLine("if(Object.prototype.hasOwnProperty.call(" + importedId + ", \"" + name + "\")) {"); - - _this13._emitLine("var " + id + " = " + importedId + "." + name + ";"); - - _this13._emitLine('} else {'); - - _this13._emitLine("cb(new Error(\"cannot import '" + name + "'\")); return;"); - - _this13._emitLine('}'); - - frame.set(alias, id); - - if (frame.parent) { - _this13._emitLine("frame.set(\"" + alias + "\", " + id + ");"); - } else { - _this13._emitLine("context.setVariable(\"" + alias + "\", " + id + ");"); - } - }); - }; - - _proto.compileBlock = function compileBlock(node) { - var id = this._tmpid(); // If we are executing outside a block (creating a top-level - // block), we really don't want to execute its code because it - // will execute twice: once when the child template runs and - // again when the parent template runs. Note that blocks - // within blocks will *always* execute immediately *and* - // wherever else they are invoked (like used in a parent - // template). This may have behavioral differences from jinja - // because blocks can have side effects, but it seems like a - // waste of performance to always execute huge top-level - // blocks twice - - - if (!this.inBlock) { - this._emit('(parentTemplate ? function(e, c, f, r, cb) { cb(""); } : '); - } - - this._emit("context.getBlock(\"" + node.name.value + "\")"); - - if (!this.inBlock) { - this._emit(')'); - } - - this._emitLine('(env, context, frame, runtime, ' + this._makeCallback(id)); - - this._emitLine(this.buffer + " += " + id + ";"); - - this._addScopeLevel(); - }; - - _proto.compileSuper = function compileSuper(node, frame) { - var name = node.blockName.value; - var id = node.symbol.value; - - var cb = this._makeCallback(id); - - this._emitLine("context.getSuper(env, \"" + name + "\", b_" + name + ", frame, runtime, " + cb); - - this._emitLine(id + " = runtime.markSafe(" + id + ");"); - - this._addScopeLevel(); - - frame.set(id, id); - }; - - _proto.compileExtends = function compileExtends(node, frame) { - var k = this._tmpid(); - - var parentTemplateId = this._compileGetTemplate(node, frame, true, false); // extends is a dynamic tag and can occur within a block like - // `if`, so if this happens we need to capture the parent - // template in the top-level scope - - - this._emitLine("parentTemplate = " + parentTemplateId); - - this._emitLine("for(var " + k + " in parentTemplate.blocks) {"); - - this._emitLine("context.addBlock(" + k + ", parentTemplate.blocks[" + k + "]);"); - - this._emitLine('}'); - - this._addScopeLevel(); - }; - - _proto.compileInclude = function compileInclude(node, frame) { - this._emitLine('var tasks = [];'); - - this._emitLine('tasks.push('); - - this._emitLine('function(callback) {'); - - var id = this._compileGetTemplate(node, frame, false, node.ignoreMissing); - - this._emitLine("callback(null," + id + ");});"); - - this._emitLine('});'); - - var id2 = this._tmpid(); - - this._emitLine('tasks.push('); - - this._emitLine('function(template, callback){'); - - this._emitLine('template.render(context.getVariables(), frame, ' + this._makeCallback(id2)); - - this._emitLine('callback(null,' + id2 + ');});'); - - this._emitLine('});'); - - this._emitLine('tasks.push('); - - this._emitLine('function(result, callback){'); - - this._emitLine(this.buffer + " += result;"); - - this._emitLine('callback(null);'); - - this._emitLine('});'); - - this._emitLine('env.waterfall(tasks, function(){'); - - this._addScopeLevel(); - }; - - _proto.compileTemplateData = function compileTemplateData(node, frame) { - this.compileLiteral(node, frame); - }; - - _proto.compileCapture = function compileCapture(node, frame) { - var _this14 = this; - - // we need to temporarily override the current buffer id as 'output' - // so the set block writes to the capture output instead of the buffer - var buffer = this.buffer; - this.buffer = 'output'; - - this._emitLine('(function() {'); - - this._emitLine('var output = "";'); - - this._withScopedSyntax(function () { - _this14.compile(node.body, frame); - }); - - this._emitLine('return output;'); - - this._emitLine('})()'); // and of course, revert back to the old buffer id - - - this.buffer = buffer; - }; - - _proto.compileOutput = function compileOutput(node, frame) { - var _this15 = this; - - var children = node.children; - children.forEach(function (child) { - // TemplateData is a special case because it is never - // autoescaped, so simply output it for optimization - if (child instanceof nodes.TemplateData) { - if (child.value) { - _this15._emit(_this15.buffer + " += "); - - _this15.compileLiteral(child, frame); - - _this15._emitLine(';'); - } - } else { - _this15._emit(_this15.buffer + " += runtime.suppressValue("); - - if (_this15.throwOnUndefined) { - _this15._emit('runtime.ensureDefined('); - } - - _this15.compile(child, frame); - - if (_this15.throwOnUndefined) { - _this15._emit("," + node.lineno + "," + node.colno + ")"); - } - - _this15._emit(', env.opts.autoescape);\n'); - } - }); - }; - - _proto.compileRoot = function compileRoot(node, frame) { - var _this16 = this; - - if (frame) { - this.fail('compileRoot: root node can\'t have frame'); - } - - frame = new Frame(); - - this._emitFuncBegin(node, 'root'); - - this._emitLine('var parentTemplate = null;'); - - this._compileChildren(node, frame); - - this._emitLine('if(parentTemplate) {'); - - this._emitLine('parentTemplate.rootRenderFunc(env, context, frame, runtime, cb);'); - - this._emitLine('} else {'); - - this._emitLine("cb(null, " + this.buffer + ");"); - - this._emitLine('}'); - - this._emitFuncEnd(true); - - this.inBlock = true; - var blockNames = []; - var blocks = node.findAll(nodes.Block); - blocks.forEach(function (block, i) { - var name = block.name.value; - - if (blockNames.indexOf(name) !== -1) { - throw new Error("Block \"" + name + "\" defined more than once."); - } - - blockNames.push(name); - - _this16._emitFuncBegin(block, "b_" + name); - - var tmpFrame = new Frame(); - - _this16._emitLine('var frame = frame.push(true);'); - - _this16.compile(block.body, tmpFrame); - - _this16._emitFuncEnd(); - }); - - this._emitLine('return {'); - - blocks.forEach(function (block, i) { - var blockName = "b_" + block.name.value; - - _this16._emitLine(blockName + ": " + blockName + ","); - }); - - this._emitLine('root: root\n};'); - }; - - _proto.compile = function compile(node, frame) { - var _compile = this['compile' + node.typename]; - - if (_compile) { - _compile.call(this, node, frame); - } else { - this.fail("compile: Cannot compile node: " + node.typename, node.lineno, node.colno); - } - }; - - _proto.getCode = function getCode() { - return this.codebuf.join(''); - }; - - return Compiler; -}(Obj); - -module.exports = { - compile: function compile(src, asyncFilters, extensions, name, opts) { - if (opts === void 0) { - opts = {}; - } - - var c = new Compiler(name, opts.throwOnUndefined); // Run the extension preprocessors against the source. - - var preprocessors = (extensions || []).map(function (ext) { - return ext.preprocess; - }).filter(function (f) { - return !!f; - }); - var processedSrc = preprocessors.reduce(function (s, processor) { - return processor(s); - }, src); - c.compile(transformer.transform(parser.parse(processedSrc, extensions, opts), asyncFilters, name)); - return c.getCode(); - }, - Compiler: Compiler -}; - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } - -var path = __webpack_require__(4); - -var _require = __webpack_require__(1), - EmitterObj = _require.EmitterObj; - -module.exports = -/*#__PURE__*/ -function (_EmitterObj) { - _inheritsLoose(Loader, _EmitterObj); - - function Loader() { - return _EmitterObj.apply(this, arguments) || this; - } - - var _proto = Loader.prototype; - - _proto.resolve = function resolve(from, to) { - return path.resolve(path.dirname(from), to); - }; - - _proto.isRelative = function isRelative(filename) { - return filename.indexOf('./') === 0 || filename.indexOf('../') === 0; - }; - - return Loader; -}(EmitterObj); - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } - -var asap = __webpack_require__(12); - -var _waterfall = __webpack_require__(15); - -var lib = __webpack_require__(0); - -var compiler = __webpack_require__(5); - -var filters = __webpack_require__(18); - -var _require = __webpack_require__(10), - FileSystemLoader = _require.FileSystemLoader, - WebLoader = _require.WebLoader, - PrecompiledLoader = _require.PrecompiledLoader; - -var tests = __webpack_require__(20); - -var globals = __webpack_require__(21); - -var _require2 = __webpack_require__(1), - Obj = _require2.Obj, - EmitterObj = _require2.EmitterObj; - -var globalRuntime = __webpack_require__(2); - -var handleError = globalRuntime.handleError, - Frame = globalRuntime.Frame; - -var expressApp = __webpack_require__(22); // If the user is using the async API, *always* call it -// asynchronously even if the template was synchronous. - - -function callbackAsap(cb, err, res) { - asap(function () { - cb(err, res); - }); -} -/** - * A no-op template, for use with {% include ignore missing %} - */ - - -var noopTmplSrc = { - type: 'code', - obj: { - root: function root(env, context, frame, runtime, cb) { - try { - cb(null, ''); - } catch (e) { - cb(handleError(e, null, null)); - } - } - } -}; - -var Environment = -/*#__PURE__*/ -function (_EmitterObj) { - _inheritsLoose(Environment, _EmitterObj); - - function Environment() { - return _EmitterObj.apply(this, arguments) || this; - } - - var _proto = Environment.prototype; - - _proto.init = function init(loaders, opts) { - var _this = this; - - // The dev flag determines the trace that'll be shown on errors. - // If set to true, returns the full trace from the error point, - // otherwise will return trace starting from Template.render - // (the full trace from within nunjucks may confuse developers using - // the library) - // defaults to false - opts = this.opts = opts || {}; - this.opts.dev = !!opts.dev; // The autoescape flag sets global autoescaping. If true, - // every string variable will be escaped by default. - // If false, strings can be manually escaped using the `escape` filter. - // defaults to true - - this.opts.autoescape = opts.autoescape != null ? opts.autoescape : true; // If true, this will make the system throw errors if trying - // to output a null or undefined value - - this.opts.throwOnUndefined = !!opts.throwOnUndefined; - this.opts.trimBlocks = !!opts.trimBlocks; - this.opts.lstripBlocks = !!opts.lstripBlocks; - this.loaders = []; - - if (!loaders) { - // The filesystem loader is only available server-side - if (FileSystemLoader) { - this.loaders = [new FileSystemLoader('views')]; - } else if (WebLoader) { - this.loaders = [new WebLoader('/views')]; - } - } else { - this.loaders = lib.isArray(loaders) ? loaders : [loaders]; - } // It's easy to use precompiled templates: just include them - // before you configure nunjucks and this will automatically - // pick it up and use it - - - if (typeof window !== 'undefined' && window.nunjucksPrecompiled) { - this.loaders.unshift(new PrecompiledLoader(window.nunjucksPrecompiled)); - } - - this._initLoaders(); - - this.globals = globals(); - this.filters = {}; - this.tests = {}; - this.asyncFilters = []; - this.extensions = {}; - this.extensionsList = []; - - lib._entries(filters).forEach(function (_ref) { - var name = _ref[0], - filter = _ref[1]; - return _this.addFilter(name, filter); - }); - - lib._entries(tests).forEach(function (_ref2) { - var name = _ref2[0], - test = _ref2[1]; - return _this.addTest(name, test); - }); - }; - - _proto._initLoaders = function _initLoaders() { - var _this2 = this; - - this.loaders.forEach(function (loader) { - // Caching and cache busting - loader.cache = {}; - - if (typeof loader.on === 'function') { - loader.on('update', function (name, fullname) { - loader.cache[name] = null; - - _this2.emit('update', name, fullname, loader); - }); - loader.on('load', function (name, source) { - _this2.emit('load', name, source, loader); - }); - } - }); - }; - - _proto.invalidateCache = function invalidateCache() { - this.loaders.forEach(function (loader) { - loader.cache = {}; - }); - }; - - _proto.addExtension = function addExtension(name, extension) { - extension.__name = name; - this.extensions[name] = extension; - this.extensionsList.push(extension); - return this; - }; - - _proto.removeExtension = function removeExtension(name) { - var extension = this.getExtension(name); - - if (!extension) { - return; - } - - this.extensionsList = lib.without(this.extensionsList, extension); - delete this.extensions[name]; - }; - - _proto.getExtension = function getExtension(name) { - return this.extensions[name]; - }; - - _proto.hasExtension = function hasExtension(name) { - return !!this.extensions[name]; - }; - - _proto.addGlobal = function addGlobal(name, value) { - this.globals[name] = value; - return this; - }; - - _proto.getGlobal = function getGlobal(name) { - if (typeof this.globals[name] === 'undefined') { - throw new Error('global not found: ' + name); - } - - return this.globals[name]; - }; - - _proto.addFilter = function addFilter(name, func, async) { - var wrapped = func; - - if (async) { - this.asyncFilters.push(name); - } - - this.filters[name] = wrapped; - return this; - }; - - _proto.getFilter = function getFilter(name) { - if (!this.filters[name]) { - throw new Error('filter not found: ' + name); - } - - return this.filters[name]; - }; - - _proto.addTest = function addTest(name, func) { - this.tests[name] = func; - return this; - }; - - _proto.getTest = function getTest(name) { - if (!this.tests[name]) { - throw new Error('test not found: ' + name); - } - - return this.tests[name]; - }; - - _proto.resolveTemplate = function resolveTemplate(loader, parentName, filename) { - var isRelative = loader.isRelative && parentName ? loader.isRelative(filename) : false; - return isRelative && loader.resolve ? loader.resolve(parentName, filename) : filename; - }; - - _proto.getTemplate = function getTemplate(name, eagerCompile, parentName, ignoreMissing, cb) { - var _this3 = this; - - var that = this; - var tmpl = null; - - if (name && name.raw) { - // this fixes autoescape for templates referenced in symbols - name = name.raw; - } - - if (lib.isFunction(parentName)) { - cb = parentName; - parentName = null; - eagerCompile = eagerCompile || false; - } - - if (lib.isFunction(eagerCompile)) { - cb = eagerCompile; - eagerCompile = false; - } - - if (name instanceof Template) { - tmpl = name; - } else if (typeof name !== 'string') { - throw new Error('template names must be a string: ' + name); - } else { - for (var i = 0; i < this.loaders.length; i++) { - var loader = this.loaders[i]; - tmpl = loader.cache[this.resolveTemplate(loader, parentName, name)]; - - if (tmpl) { - break; - } - } - } - - if (tmpl) { - if (eagerCompile) { - tmpl.compile(); - } - - if (cb) { - cb(null, tmpl); - return undefined; - } else { - return tmpl; - } - } - - var syncResult; - - var createTemplate = function createTemplate(err, info) { - if (!info && !err && !ignoreMissing) { - err = new Error('template not found: ' + name); - } - - if (err) { - if (cb) { - cb(err); - return; - } else { - throw err; - } - } - - var newTmpl; - - if (!info) { - newTmpl = new Template(noopTmplSrc, _this3, '', eagerCompile); - } else { - newTmpl = new Template(info.src, _this3, info.path, eagerCompile); - - if (!info.noCache) { - info.loader.cache[name] = newTmpl; - } - } - - if (cb) { - cb(null, newTmpl); - } else { - syncResult = newTmpl; - } - }; - - lib.asyncIter(this.loaders, function (loader, i, next, done) { - function handle(err, src) { - if (err) { - done(err); - } else if (src) { - src.loader = loader; - done(null, src); - } else { - next(); - } - } // Resolve name relative to parentName - - - name = that.resolveTemplate(loader, parentName, name); - - if (loader.async) { - loader.getSource(name, handle); - } else { - handle(null, loader.getSource(name)); - } - }, createTemplate); - return syncResult; - }; - - _proto.express = function express(app) { - return expressApp(this, app); - }; - - _proto.render = function render(name, ctx, cb) { - if (lib.isFunction(ctx)) { - cb = ctx; - ctx = null; - } // We support a synchronous API to make it easier to migrate - // existing code to async. This works because if you don't do - // anything async work, the whole thing is actually run - // synchronously. - - - var syncResult = null; - this.getTemplate(name, function (err, tmpl) { - if (err && cb) { - callbackAsap(cb, err); - } else if (err) { - throw err; - } else { - syncResult = tmpl.render(ctx, cb); - } - }); - return syncResult; - }; - - _proto.renderString = function renderString(src, ctx, opts, cb) { - if (lib.isFunction(opts)) { - cb = opts; - opts = {}; - } - - opts = opts || {}; - var tmpl = new Template(src, this, opts.path); - return tmpl.render(ctx, cb); - }; - - _proto.waterfall = function waterfall(tasks, callback, forceAsync) { - return _waterfall(tasks, callback, forceAsync); - }; - - return Environment; -}(EmitterObj); - -var Context = -/*#__PURE__*/ -function (_Obj) { - _inheritsLoose(Context, _Obj); - - function Context() { - return _Obj.apply(this, arguments) || this; - } - - var _proto2 = Context.prototype; - - _proto2.init = function init(ctx, blocks, env) { - var _this4 = this; - - // Has to be tied to an environment so we can tap into its globals. - this.env = env || new Environment(); // Make a duplicate of ctx - - this.ctx = lib.extend({}, ctx); - this.blocks = {}; - this.exported = []; - lib.keys(blocks).forEach(function (name) { - _this4.addBlock(name, blocks[name]); - }); - }; - - _proto2.lookup = function lookup(name) { - // This is one of the most called functions, so optimize for - // the typical case where the name isn't in the globals - if (name in this.env.globals && !(name in this.ctx)) { - return this.env.globals[name]; - } else { - return this.ctx[name]; - } - }; - - _proto2.setVariable = function setVariable(name, val) { - this.ctx[name] = val; - }; - - _proto2.getVariables = function getVariables() { - return this.ctx; - }; - - _proto2.addBlock = function addBlock(name, block) { - this.blocks[name] = this.blocks[name] || []; - this.blocks[name].push(block); - return this; - }; - - _proto2.getBlock = function getBlock(name) { - if (!this.blocks[name]) { - throw new Error('unknown block "' + name + '"'); - } - - return this.blocks[name][0]; - }; - - _proto2.getSuper = function getSuper(env, name, block, frame, runtime, cb) { - var idx = lib.indexOf(this.blocks[name] || [], block); - var blk = this.blocks[name][idx + 1]; - var context = this; - - if (idx === -1 || !blk) { - throw new Error('no super block available for "' + name + '"'); - } - - blk(env, context, frame, runtime, cb); - }; - - _proto2.addExport = function addExport(name) { - this.exported.push(name); - }; - - _proto2.getExported = function getExported() { - var _this5 = this; - - var exported = {}; - this.exported.forEach(function (name) { - exported[name] = _this5.ctx[name]; - }); - return exported; - }; - - return Context; -}(Obj); - -var Template = -/*#__PURE__*/ -function (_Obj2) { - _inheritsLoose(Template, _Obj2); - - function Template() { - return _Obj2.apply(this, arguments) || this; - } - - var _proto3 = Template.prototype; - - _proto3.init = function init(src, env, path, eagerCompile) { - this.env = env || new Environment(); - - if (lib.isObject(src)) { - switch (src.type) { - case 'code': - this.tmplProps = src.obj; - break; - - case 'string': - this.tmplStr = src.obj; - break; - - default: - throw new Error("Unexpected template object type " + src.type + "; expected 'code', or 'string'"); - } - } else if (lib.isString(src)) { - this.tmplStr = src; - } else { - throw new Error('src must be a string or an object describing the source'); - } - - this.path = path; - - if (eagerCompile) { - try { - this._compile(); - } catch (err) { - throw lib._prettifyError(this.path, this.env.opts.dev, err); - } - } else { - this.compiled = false; - } - }; - - _proto3.render = function render(ctx, parentFrame, cb) { - var _this6 = this; - - if (typeof ctx === 'function') { - cb = ctx; - ctx = {}; - } else if (typeof parentFrame === 'function') { - cb = parentFrame; - parentFrame = null; - } // If there is a parent frame, we are being called from internal - // code of another template, and the internal system - // depends on the sync/async nature of the parent template - // to be inherited, so force an async callback - - - var forceAsync = !parentFrame; // Catch compile errors for async rendering - - try { - this.compile(); - } catch (e) { - var err = lib._prettifyError(this.path, this.env.opts.dev, e); - - if (cb) { - return callbackAsap(cb, err); - } else { - throw err; - } - } - - var context = new Context(ctx || {}, this.blocks, this.env); - var frame = parentFrame ? parentFrame.push(true) : new Frame(); - frame.topLevel = true; - var syncResult = null; - var didError = false; - this.rootRenderFunc(this.env, context, frame, globalRuntime, function (err, res) { - // TODO: this is actually a bug in the compiled template (because waterfall - // tasks are both not passing errors up the chain of callbacks AND are not - // causing a return from the top-most render function). But fixing that - // will require a more substantial change to the compiler. - if (didError && cb && typeof res !== 'undefined') { - // prevent multiple calls to cb - return; - } - - if (err) { - err = lib._prettifyError(_this6.path, _this6.env.opts.dev, err); - didError = true; - } - - if (cb) { - if (forceAsync) { - callbackAsap(cb, err, res); - } else { - cb(err, res); - } - } else { - if (err) { - throw err; - } - - syncResult = res; - } - }); - return syncResult; - }; - - _proto3.getExported = function getExported(ctx, parentFrame, cb) { - // eslint-disable-line consistent-return - if (typeof ctx === 'function') { - cb = ctx; - ctx = {}; - } - - if (typeof parentFrame === 'function') { - cb = parentFrame; - parentFrame = null; - } // Catch compile errors for async rendering - - - try { - this.compile(); - } catch (e) { - if (cb) { - return cb(e); - } else { - throw e; - } - } - - var frame = parentFrame ? parentFrame.push() : new Frame(); - frame.topLevel = true; // Run the rootRenderFunc to populate the context with exported vars - - var context = new Context(ctx || {}, this.blocks, this.env); - this.rootRenderFunc(this.env, context, frame, globalRuntime, function (err) { - if (err) { - cb(err, null); - } else { - cb(null, context.getExported()); - } - }); - }; - - _proto3.compile = function compile() { - if (!this.compiled) { - this._compile(); - } - }; - - _proto3._compile = function _compile() { - var props; - - if (this.tmplProps) { - props = this.tmplProps; - } else { - var source = compiler.compile(this.tmplStr, this.env.asyncFilters, this.env.extensionsList, this.path, this.env.opts); - var func = new Function(source); // eslint-disable-line no-new-func - - props = func(); - } - - this.blocks = this._getBlocks(props); - this.rootRenderFunc = props.root; - this.compiled = true; - }; - - _proto3._getBlocks = function _getBlocks(props) { - var blocks = {}; - lib.keys(props).forEach(function (k) { - if (k.slice(0, 2) === 'b_') { - blocks[k.slice(2)] = props[k]; - } - }); - return blocks; - }; - - return Template; -}(Obj); - -module.exports = { - Environment: Environment, - Template: Template -}; - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } - -var lexer = __webpack_require__(9); - -var nodes = __webpack_require__(3); - -var Obj = __webpack_require__(1).Obj; - -var lib = __webpack_require__(0); - -var Parser = -/*#__PURE__*/ -function (_Obj) { - _inheritsLoose(Parser, _Obj); - - function Parser() { - return _Obj.apply(this, arguments) || this; - } - - var _proto = Parser.prototype; - - _proto.init = function init(tokens) { - this.tokens = tokens; - this.peeked = null; - this.breakOnBlocks = null; - this.dropLeadingWhitespace = false; - this.extensions = []; - }; - - _proto.nextToken = function nextToken(withWhitespace) { - var tok; - - if (this.peeked) { - if (!withWhitespace && this.peeked.type === lexer.TOKEN_WHITESPACE) { - this.peeked = null; - } else { - tok = this.peeked; - this.peeked = null; - return tok; - } - } - - tok = this.tokens.nextToken(); - - if (!withWhitespace) { - while (tok && tok.type === lexer.TOKEN_WHITESPACE) { - tok = this.tokens.nextToken(); - } - } - - return tok; - }; - - _proto.peekToken = function peekToken() { - this.peeked = this.peeked || this.nextToken(); - return this.peeked; - }; - - _proto.pushToken = function pushToken(tok) { - if (this.peeked) { - throw new Error('pushToken: can only push one token on between reads'); - } - - this.peeked = tok; - }; - - _proto.error = function error(msg, lineno, colno) { - if (lineno === undefined || colno === undefined) { - var tok = this.peekToken() || {}; - lineno = tok.lineno; - colno = tok.colno; - } - - if (lineno !== undefined) { - lineno += 1; - } - - if (colno !== undefined) { - colno += 1; - } - - return new lib.TemplateError(msg, lineno, colno); - }; - - _proto.fail = function fail(msg, lineno, colno) { - throw this.error(msg, lineno, colno); - }; - - _proto.skip = function skip(type) { - var tok = this.nextToken(); - - if (!tok || tok.type !== type) { - this.pushToken(tok); - return false; - } - - return true; - }; - - _proto.expect = function expect(type) { - var tok = this.nextToken(); - - if (tok.type !== type) { - this.fail('expected ' + type + ', got ' + tok.type, tok.lineno, tok.colno); - } - - return tok; - }; - - _proto.skipValue = function skipValue(type, val) { - var tok = this.nextToken(); - - if (!tok || tok.type !== type || tok.value !== val) { - this.pushToken(tok); - return false; - } - - return true; - }; - - _proto.skipSymbol = function skipSymbol(val) { - return this.skipValue(lexer.TOKEN_SYMBOL, val); - }; - - _proto.advanceAfterBlockEnd = function advanceAfterBlockEnd(name) { - var tok; - - if (!name) { - tok = this.peekToken(); - - if (!tok) { - this.fail('unexpected end of file'); - } - - if (tok.type !== lexer.TOKEN_SYMBOL) { - this.fail('advanceAfterBlockEnd: expected symbol token or ' + 'explicit name to be passed'); - } - - name = this.nextToken().value; - } - - tok = this.nextToken(); - - if (tok && tok.type === lexer.TOKEN_BLOCK_END) { - if (tok.value.charAt(0) === '-') { - this.dropLeadingWhitespace = true; - } - } else { - this.fail('expected block end in ' + name + ' statement'); - } - - return tok; - }; - - _proto.advanceAfterVariableEnd = function advanceAfterVariableEnd() { - var tok = this.nextToken(); - - if (tok && tok.type === lexer.TOKEN_VARIABLE_END) { - this.dropLeadingWhitespace = tok.value.charAt(tok.value.length - this.tokens.tags.VARIABLE_END.length - 1) === '-'; - } else { - this.pushToken(tok); - this.fail('expected variable end'); - } - }; - - _proto.parseFor = function parseFor() { - var forTok = this.peekToken(); - var node; - var endBlock; - - if (this.skipSymbol('for')) { - node = new nodes.For(forTok.lineno, forTok.colno); - endBlock = 'endfor'; - } else if (this.skipSymbol('asyncEach')) { - node = new nodes.AsyncEach(forTok.lineno, forTok.colno); - endBlock = 'endeach'; - } else if (this.skipSymbol('asyncAll')) { - node = new nodes.AsyncAll(forTok.lineno, forTok.colno); - endBlock = 'endall'; - } else { - this.fail('parseFor: expected for{Async}', forTok.lineno, forTok.colno); - } - - node.name = this.parsePrimary(); - - if (!(node.name instanceof nodes.Symbol)) { - this.fail('parseFor: variable name expected for loop'); - } - - var type = this.peekToken().type; - - if (type === lexer.TOKEN_COMMA) { - // key/value iteration - var key = node.name; - node.name = new nodes.Array(key.lineno, key.colno); - node.name.addChild(key); - - while (this.skip(lexer.TOKEN_COMMA)) { - var prim = this.parsePrimary(); - node.name.addChild(prim); - } - } - - if (!this.skipSymbol('in')) { - this.fail('parseFor: expected "in" keyword for loop', forTok.lineno, forTok.colno); - } - - node.arr = this.parseExpression(); - this.advanceAfterBlockEnd(forTok.value); - node.body = this.parseUntilBlocks(endBlock, 'else'); - - if (this.skipSymbol('else')) { - this.advanceAfterBlockEnd('else'); - node.else_ = this.parseUntilBlocks(endBlock); - } - - this.advanceAfterBlockEnd(); - return node; - }; - - _proto.parseMacro = function parseMacro() { - var macroTok = this.peekToken(); - - if (!this.skipSymbol('macro')) { - this.fail('expected macro'); - } - - var name = this.parsePrimary(true); - var args = this.parseSignature(); - var node = new nodes.Macro(macroTok.lineno, macroTok.colno, name, args); - this.advanceAfterBlockEnd(macroTok.value); - node.body = this.parseUntilBlocks('endmacro'); - this.advanceAfterBlockEnd(); - return node; - }; - - _proto.parseCall = function parseCall() { - // a call block is parsed as a normal FunCall, but with an added - // 'caller' kwarg which is a Caller node. - var callTok = this.peekToken(); - - if (!this.skipSymbol('call')) { - this.fail('expected call'); - } - - var callerArgs = this.parseSignature(true) || new nodes.NodeList(); - var macroCall = this.parsePrimary(); - this.advanceAfterBlockEnd(callTok.value); - var body = this.parseUntilBlocks('endcall'); - this.advanceAfterBlockEnd(); - var callerName = new nodes.Symbol(callTok.lineno, callTok.colno, 'caller'); - var callerNode = new nodes.Caller(callTok.lineno, callTok.colno, callerName, callerArgs, body); // add the additional caller kwarg, adding kwargs if necessary - - var args = macroCall.args.children; - - if (!(args[args.length - 1] instanceof nodes.KeywordArgs)) { - args.push(new nodes.KeywordArgs()); - } - - var kwargs = args[args.length - 1]; - kwargs.addChild(new nodes.Pair(callTok.lineno, callTok.colno, callerName, callerNode)); - return new nodes.Output(callTok.lineno, callTok.colno, [macroCall]); - }; - - _proto.parseWithContext = function parseWithContext() { - var tok = this.peekToken(); - var withContext = null; - - if (this.skipSymbol('with')) { - withContext = true; - } else if (this.skipSymbol('without')) { - withContext = false; - } - - if (withContext !== null) { - if (!this.skipSymbol('context')) { - this.fail('parseFrom: expected context after with/without', tok.lineno, tok.colno); - } - } - - return withContext; - }; - - _proto.parseImport = function parseImport() { - var importTok = this.peekToken(); - - if (!this.skipSymbol('import')) { - this.fail('parseImport: expected import', importTok.lineno, importTok.colno); - } - - var template = this.parseExpression(); - - if (!this.skipSymbol('as')) { - this.fail('parseImport: expected "as" keyword', importTok.lineno, importTok.colno); - } - - var target = this.parseExpression(); - var withContext = this.parseWithContext(); - var node = new nodes.Import(importTok.lineno, importTok.colno, template, target, withContext); - this.advanceAfterBlockEnd(importTok.value); - return node; - }; - - _proto.parseFrom = function parseFrom() { - var fromTok = this.peekToken(); - - if (!this.skipSymbol('from')) { - this.fail('parseFrom: expected from'); - } - - var template = this.parseExpression(); - - if (!this.skipSymbol('import')) { - this.fail('parseFrom: expected import', fromTok.lineno, fromTok.colno); - } - - var names = new nodes.NodeList(); - var withContext; - - while (1) { - // eslint-disable-line no-constant-condition - var nextTok = this.peekToken(); - - if (nextTok.type === lexer.TOKEN_BLOCK_END) { - if (!names.children.length) { - this.fail('parseFrom: Expected at least one import name', fromTok.lineno, fromTok.colno); - } // Since we are manually advancing past the block end, - // need to keep track of whitespace control (normally - // this is done in `advanceAfterBlockEnd` - - - if (nextTok.value.charAt(0) === '-') { - this.dropLeadingWhitespace = true; - } - - this.nextToken(); - break; - } - - if (names.children.length > 0 && !this.skip(lexer.TOKEN_COMMA)) { - this.fail('parseFrom: expected comma', fromTok.lineno, fromTok.colno); - } - - var name = this.parsePrimary(); - - if (name.value.charAt(0) === '_') { - this.fail('parseFrom: names starting with an underscore cannot be imported', name.lineno, name.colno); - } - - if (this.skipSymbol('as')) { - var alias = this.parsePrimary(); - names.addChild(new nodes.Pair(name.lineno, name.colno, name, alias)); - } else { - names.addChild(name); - } - - withContext = this.parseWithContext(); - } - - return new nodes.FromImport(fromTok.lineno, fromTok.colno, template, names, withContext); - }; - - _proto.parseBlock = function parseBlock() { - var tag = this.peekToken(); - - if (!this.skipSymbol('block')) { - this.fail('parseBlock: expected block', tag.lineno, tag.colno); - } - - var node = new nodes.Block(tag.lineno, tag.colno); - node.name = this.parsePrimary(); - - if (!(node.name instanceof nodes.Symbol)) { - this.fail('parseBlock: variable name expected', tag.lineno, tag.colno); - } - - this.advanceAfterBlockEnd(tag.value); - node.body = this.parseUntilBlocks('endblock'); - this.skipSymbol('endblock'); - this.skipSymbol(node.name.value); - var tok = this.peekToken(); - - if (!tok) { - this.fail('parseBlock: expected endblock, got end of file'); - } - - this.advanceAfterBlockEnd(tok.value); - return node; - }; - - _proto.parseExtends = function parseExtends() { - var tagName = 'extends'; - var tag = this.peekToken(); - - if (!this.skipSymbol(tagName)) { - this.fail('parseTemplateRef: expected ' + tagName); - } - - var node = new nodes.Extends(tag.lineno, tag.colno); - node.template = this.parseExpression(); - this.advanceAfterBlockEnd(tag.value); - return node; - }; - - _proto.parseInclude = function parseInclude() { - var tagName = 'include'; - var tag = this.peekToken(); - - if (!this.skipSymbol(tagName)) { - this.fail('parseInclude: expected ' + tagName); - } - - var node = new nodes.Include(tag.lineno, tag.colno); - node.template = this.parseExpression(); - - if (this.skipSymbol('ignore') && this.skipSymbol('missing')) { - node.ignoreMissing = true; - } - - this.advanceAfterBlockEnd(tag.value); - return node; - }; - - _proto.parseIf = function parseIf() { - var tag = this.peekToken(); - var node; - - if (this.skipSymbol('if') || this.skipSymbol('elif') || this.skipSymbol('elseif')) { - node = new nodes.If(tag.lineno, tag.colno); - } else if (this.skipSymbol('ifAsync')) { - node = new nodes.IfAsync(tag.lineno, tag.colno); - } else { - this.fail('parseIf: expected if, elif, or elseif', tag.lineno, tag.colno); - } - - node.cond = this.parseExpression(); - this.advanceAfterBlockEnd(tag.value); - node.body = this.parseUntilBlocks('elif', 'elseif', 'else', 'endif'); - var tok = this.peekToken(); - - switch (tok && tok.value) { - case 'elseif': - case 'elif': - node.else_ = this.parseIf(); - break; - - case 'else': - this.advanceAfterBlockEnd(); - node.else_ = this.parseUntilBlocks('endif'); - this.advanceAfterBlockEnd(); - break; - - case 'endif': - node.else_ = null; - this.advanceAfterBlockEnd(); - break; - - default: - this.fail('parseIf: expected elif, else, or endif, got end of file'); - } - - return node; - }; - - _proto.parseSet = function parseSet() { - var tag = this.peekToken(); - - if (!this.skipSymbol('set')) { - this.fail('parseSet: expected set', tag.lineno, tag.colno); - } - - var node = new nodes.Set(tag.lineno, tag.colno, []); - var target; - - while (target = this.parsePrimary()) { - node.targets.push(target); - - if (!this.skip(lexer.TOKEN_COMMA)) { - break; - } - } - - if (!this.skipValue(lexer.TOKEN_OPERATOR, '=')) { - if (!this.skip(lexer.TOKEN_BLOCK_END)) { - this.fail('parseSet: expected = or block end in set tag', tag.lineno, tag.colno); - } else { - node.body = new nodes.Capture(tag.lineno, tag.colno, this.parseUntilBlocks('endset')); - node.value = null; - this.advanceAfterBlockEnd(); - } - } else { - node.value = this.parseExpression(); - this.advanceAfterBlockEnd(tag.value); - } - - return node; - }; - - _proto.parseSwitch = function parseSwitch() { - /* - * Store the tag names in variables in case someone ever wants to - * customize this. - */ - var switchStart = 'switch'; - var switchEnd = 'endswitch'; - var caseStart = 'case'; - var caseDefault = 'default'; // Get the switch tag. - - var tag = this.peekToken(); // fail early if we get some unexpected tag. - - if (!this.skipSymbol(switchStart) && !this.skipSymbol(caseStart) && !this.skipSymbol(caseDefault)) { - this.fail('parseSwitch: expected "switch," "case" or "default"', tag.lineno, tag.colno); - } // parse the switch expression - - - var expr = this.parseExpression(); // advance until a start of a case, a default case or an endswitch. - - this.advanceAfterBlockEnd(switchStart); - this.parseUntilBlocks(caseStart, caseDefault, switchEnd); // this is the first case. it could also be an endswitch, we'll check. - - var tok = this.peekToken(); // create new variables for our cases and default case. - - var cases = []; - var defaultCase; // while we're dealing with new cases nodes... - - do { - // skip the start symbol and get the case expression - this.skipSymbol(caseStart); - var cond = this.parseExpression(); - this.advanceAfterBlockEnd(switchStart); // get the body of the case node and add it to the array of cases. - - var body = this.parseUntilBlocks(caseStart, caseDefault, switchEnd); - cases.push(new nodes.Case(tok.line, tok.col, cond, body)); // get our next case - - tok = this.peekToken(); - } while (tok && tok.value === caseStart); // we either have a default case or a switch end. - - - switch (tok.value) { - case caseDefault: - this.advanceAfterBlockEnd(); - defaultCase = this.parseUntilBlocks(switchEnd); - this.advanceAfterBlockEnd(); - break; - - case switchEnd: - this.advanceAfterBlockEnd(); - break; - - default: - // otherwise bail because EOF - this.fail('parseSwitch: expected "case," "default" or "endswitch," got EOF.'); - } // and return the switch node. - - - return new nodes.Switch(tag.lineno, tag.colno, expr, cases, defaultCase); - }; - - _proto.parseStatement = function parseStatement() { - var tok = this.peekToken(); - var node; - - if (tok.type !== lexer.TOKEN_SYMBOL) { - this.fail('tag name expected', tok.lineno, tok.colno); - } - - if (this.breakOnBlocks && lib.indexOf(this.breakOnBlocks, tok.value) !== -1) { - return null; - } - - switch (tok.value) { - case 'raw': - return this.parseRaw(); - - case 'verbatim': - return this.parseRaw('verbatim'); - - case 'if': - case 'ifAsync': - return this.parseIf(); - - case 'for': - case 'asyncEach': - case 'asyncAll': - return this.parseFor(); - - case 'block': - return this.parseBlock(); - - case 'extends': - return this.parseExtends(); - - case 'include': - return this.parseInclude(); - - case 'set': - return this.parseSet(); - - case 'macro': - return this.parseMacro(); - - case 'call': - return this.parseCall(); - - case 'import': - return this.parseImport(); - - case 'from': - return this.parseFrom(); - - case 'filter': - return this.parseFilterStatement(); - - case 'switch': - return this.parseSwitch(); - - default: - if (this.extensions.length) { - for (var i = 0; i < this.extensions.length; i++) { - var ext = this.extensions[i]; - - if (lib.indexOf(ext.tags || [], tok.value) !== -1) { - return ext.parse(this, nodes, lexer); - } - } - } - - this.fail('unknown block tag: ' + tok.value, tok.lineno, tok.colno); - } - - return node; - }; - - _proto.parseRaw = function parseRaw(tagName) { - tagName = tagName || 'raw'; - var endTagName = 'end' + tagName; // Look for upcoming raw blocks (ignore all other kinds of blocks) - - var rawBlockRegex = new RegExp('([\\s\\S]*?){%\\s*(' + tagName + '|' + endTagName + ')\\s*(?=%})%}'); - var rawLevel = 1; - var str = ''; - var matches = null; // Skip opening raw token - // Keep this token to track line and column numbers - - var begun = this.advanceAfterBlockEnd(); // Exit when there's nothing to match - // or when we've found the matching "endraw" block - - while ((matches = this.tokens._extractRegex(rawBlockRegex)) && rawLevel > 0) { - var all = matches[0]; - var pre = matches[1]; - var blockName = matches[2]; // Adjust rawlevel - - if (blockName === tagName) { - rawLevel += 1; - } else if (blockName === endTagName) { - rawLevel -= 1; - } // Add to str - - - if (rawLevel === 0) { - // We want to exclude the last "endraw" - str += pre; // Move tokenizer to beginning of endraw block - - this.tokens.backN(all.length - pre.length); - } else { - str += all; - } - } - - return new nodes.Output(begun.lineno, begun.colno, [new nodes.TemplateData(begun.lineno, begun.colno, str)]); - }; - - _proto.parsePostfix = function parsePostfix(node) { - var lookup; - var tok = this.peekToken(); - - while (tok) { - if (tok.type === lexer.TOKEN_LEFT_PAREN) { - // Function call - node = new nodes.FunCall(tok.lineno, tok.colno, node, this.parseSignature()); - } else if (tok.type === lexer.TOKEN_LEFT_BRACKET) { - // Reference - lookup = this.parseAggregate(); - - if (lookup.children.length > 1) { - this.fail('invalid index'); - } - - node = new nodes.LookupVal(tok.lineno, tok.colno, node, lookup.children[0]); - } else if (tok.type === lexer.TOKEN_OPERATOR && tok.value === '.') { - // Reference - this.nextToken(); - var val = this.nextToken(); - - if (val.type !== lexer.TOKEN_SYMBOL) { - this.fail('expected name as lookup value, got ' + val.value, val.lineno, val.colno); - } // Make a literal string because it's not a variable - // reference - - - lookup = new nodes.Literal(val.lineno, val.colno, val.value); - node = new nodes.LookupVal(tok.lineno, tok.colno, node, lookup); - } else { - break; - } - - tok = this.peekToken(); - } - - return node; - }; - - _proto.parseExpression = function parseExpression() { - var node = this.parseInlineIf(); - return node; - }; - - _proto.parseInlineIf = function parseInlineIf() { - var node = this.parseOr(); - - if (this.skipSymbol('if')) { - var condNode = this.parseOr(); - var bodyNode = node; - node = new nodes.InlineIf(node.lineno, node.colno); - node.body = bodyNode; - node.cond = condNode; - - if (this.skipSymbol('else')) { - node.else_ = this.parseOr(); - } else { - node.else_ = null; - } - } - - return node; - }; - - _proto.parseOr = function parseOr() { - var node = this.parseAnd(); - - while (this.skipSymbol('or')) { - var node2 = this.parseAnd(); - node = new nodes.Or(node.lineno, node.colno, node, node2); - } - - return node; - }; - - _proto.parseAnd = function parseAnd() { - var node = this.parseNot(); - - while (this.skipSymbol('and')) { - var node2 = this.parseNot(); - node = new nodes.And(node.lineno, node.colno, node, node2); - } - - return node; - }; - - _proto.parseNot = function parseNot() { - var tok = this.peekToken(); - - if (this.skipSymbol('not')) { - return new nodes.Not(tok.lineno, tok.colno, this.parseNot()); - } - - return this.parseIn(); - }; - - _proto.parseIn = function parseIn() { - var node = this.parseIs(); - - while (1) { - // eslint-disable-line no-constant-condition - // check if the next token is 'not' - var tok = this.nextToken(); - - if (!tok) { - break; - } - - var invert = tok.type === lexer.TOKEN_SYMBOL && tok.value === 'not'; // if it wasn't 'not', put it back - - if (!invert) { - this.pushToken(tok); - } - - if (this.skipSymbol('in')) { - var node2 = this.parseIs(); - node = new nodes.In(node.lineno, node.colno, node, node2); - - if (invert) { - node = new nodes.Not(node.lineno, node.colno, node); - } - } else { - // if we'd found a 'not' but this wasn't an 'in', put back the 'not' - if (invert) { - this.pushToken(tok); - } - - break; - } - } - - return node; - }; // I put this right after "in" in the operator precedence stack. That can - // obviously be changed to be closer to Jinja. - - - _proto.parseIs = function parseIs() { - var node = this.parseCompare(); // look for an is - - if (this.skipSymbol('is')) { - // look for a not - var not = this.skipSymbol('not'); // get the next node - - var node2 = this.parseCompare(); // create an Is node using the next node and the info from our Is node. - - node = new nodes.Is(node.lineno, node.colno, node, node2); // if we have a Not, create a Not node from our Is node. - - if (not) { - node = new nodes.Not(node.lineno, node.colno, node); - } - } // return the node. - - - return node; - }; - - _proto.parseCompare = function parseCompare() { - var compareOps = ['==', '===', '!=', '!==', '<', '>', '<=', '>=']; - var expr = this.parseConcat(); - var ops = []; - - while (1) { - // eslint-disable-line no-constant-condition - var tok = this.nextToken(); - - if (!tok) { - break; - } else if (compareOps.indexOf(tok.value) !== -1) { - ops.push(new nodes.CompareOperand(tok.lineno, tok.colno, this.parseConcat(), tok.value)); - } else { - this.pushToken(tok); - break; - } - } - - if (ops.length) { - return new nodes.Compare(ops[0].lineno, ops[0].colno, expr, ops); - } else { - return expr; - } - }; // finds the '~' for string concatenation - - - _proto.parseConcat = function parseConcat() { - var node = this.parseAdd(); - - while (this.skipValue(lexer.TOKEN_TILDE, '~')) { - var node2 = this.parseAdd(); - node = new nodes.Concat(node.lineno, node.colno, node, node2); - } - - return node; - }; - - _proto.parseAdd = function parseAdd() { - var node = this.parseSub(); - - while (this.skipValue(lexer.TOKEN_OPERATOR, '+')) { - var node2 = this.parseSub(); - node = new nodes.Add(node.lineno, node.colno, node, node2); - } - - return node; - }; - - _proto.parseSub = function parseSub() { - var node = this.parseMul(); - - while (this.skipValue(lexer.TOKEN_OPERATOR, '-')) { - var node2 = this.parseMul(); - node = new nodes.Sub(node.lineno, node.colno, node, node2); - } - - return node; - }; - - _proto.parseMul = function parseMul() { - var node = this.parseDiv(); - - while (this.skipValue(lexer.TOKEN_OPERATOR, '*')) { - var node2 = this.parseDiv(); - node = new nodes.Mul(node.lineno, node.colno, node, node2); - } - - return node; - }; - - _proto.parseDiv = function parseDiv() { - var node = this.parseFloorDiv(); - - while (this.skipValue(lexer.TOKEN_OPERATOR, '/')) { - var node2 = this.parseFloorDiv(); - node = new nodes.Div(node.lineno, node.colno, node, node2); - } - - return node; - }; - - _proto.parseFloorDiv = function parseFloorDiv() { - var node = this.parseMod(); - - while (this.skipValue(lexer.TOKEN_OPERATOR, '//')) { - var node2 = this.parseMod(); - node = new nodes.FloorDiv(node.lineno, node.colno, node, node2); - } - - return node; - }; - - _proto.parseMod = function parseMod() { - var node = this.parsePow(); - - while (this.skipValue(lexer.TOKEN_OPERATOR, '%')) { - var node2 = this.parsePow(); - node = new nodes.Mod(node.lineno, node.colno, node, node2); - } - - return node; - }; - - _proto.parsePow = function parsePow() { - var node = this.parseUnary(); - - while (this.skipValue(lexer.TOKEN_OPERATOR, '**')) { - var node2 = this.parseUnary(); - node = new nodes.Pow(node.lineno, node.colno, node, node2); - } - - return node; - }; - - _proto.parseUnary = function parseUnary(noFilters) { - var tok = this.peekToken(); - var node; - - if (this.skipValue(lexer.TOKEN_OPERATOR, '-')) { - node = new nodes.Neg(tok.lineno, tok.colno, this.parseUnary(true)); - } else if (this.skipValue(lexer.TOKEN_OPERATOR, '+')) { - node = new nodes.Pos(tok.lineno, tok.colno, this.parseUnary(true)); - } else { - node = this.parsePrimary(); - } - - if (!noFilters) { - node = this.parseFilter(node); - } - - return node; - }; - - _proto.parsePrimary = function parsePrimary(noPostfix) { - var tok = this.nextToken(); - var val; - var node = null; - - if (!tok) { - this.fail('expected expression, got end of file'); - } else if (tok.type === lexer.TOKEN_STRING) { - val = tok.value; - } else if (tok.type === lexer.TOKEN_INT) { - val = parseInt(tok.value, 10); - } else if (tok.type === lexer.TOKEN_FLOAT) { - val = parseFloat(tok.value); - } else if (tok.type === lexer.TOKEN_BOOLEAN) { - if (tok.value === 'true') { - val = true; - } else if (tok.value === 'false') { - val = false; - } else { - this.fail('invalid boolean: ' + tok.value, tok.lineno, tok.colno); - } - } else if (tok.type === lexer.TOKEN_NONE) { - val = null; - } else if (tok.type === lexer.TOKEN_REGEX) { - val = new RegExp(tok.value.body, tok.value.flags); - } - - if (val !== undefined) { - node = new nodes.Literal(tok.lineno, tok.colno, val); - } else if (tok.type === lexer.TOKEN_SYMBOL) { - node = new nodes.Symbol(tok.lineno, tok.colno, tok.value); - } else { - // See if it's an aggregate type, we need to push the - // current delimiter token back on - this.pushToken(tok); - node = this.parseAggregate(); - } - - if (!noPostfix) { - node = this.parsePostfix(node); - } - - if (node) { - return node; - } else { - throw this.error("unexpected token: " + tok.value, tok.lineno, tok.colno); - } - }; - - _proto.parseFilterName = function parseFilterName() { - var tok = this.expect(lexer.TOKEN_SYMBOL); - var name = tok.value; - - while (this.skipValue(lexer.TOKEN_OPERATOR, '.')) { - name += '.' + this.expect(lexer.TOKEN_SYMBOL).value; - } - - return new nodes.Symbol(tok.lineno, tok.colno, name); - }; - - _proto.parseFilterArgs = function parseFilterArgs(node) { - if (this.peekToken().type === lexer.TOKEN_LEFT_PAREN) { - // Get a FunCall node and add the parameters to the - // filter - var call = this.parsePostfix(node); - return call.args.children; - } - - return []; - }; - - _proto.parseFilter = function parseFilter(node) { - while (this.skip(lexer.TOKEN_PIPE)) { - var name = this.parseFilterName(); - node = new nodes.Filter(name.lineno, name.colno, name, new nodes.NodeList(name.lineno, name.colno, [node].concat(this.parseFilterArgs(node)))); - } - - return node; - }; - - _proto.parseFilterStatement = function parseFilterStatement() { - var filterTok = this.peekToken(); - - if (!this.skipSymbol('filter')) { - this.fail('parseFilterStatement: expected filter'); - } - - var name = this.parseFilterName(); - var args = this.parseFilterArgs(name); - this.advanceAfterBlockEnd(filterTok.value); - var body = new nodes.Capture(name.lineno, name.colno, this.parseUntilBlocks('endfilter')); - this.advanceAfterBlockEnd(); - var node = new nodes.Filter(name.lineno, name.colno, name, new nodes.NodeList(name.lineno, name.colno, [body].concat(args))); - return new nodes.Output(name.lineno, name.colno, [node]); - }; - - _proto.parseAggregate = function parseAggregate() { - var tok = this.nextToken(); - var node; - - switch (tok.type) { - case lexer.TOKEN_LEFT_PAREN: - node = new nodes.Group(tok.lineno, tok.colno); - break; - - case lexer.TOKEN_LEFT_BRACKET: - node = new nodes.Array(tok.lineno, tok.colno); - break; - - case lexer.TOKEN_LEFT_CURLY: - node = new nodes.Dict(tok.lineno, tok.colno); - break; - - default: - return null; - } - - while (1) { - // eslint-disable-line no-constant-condition - var type = this.peekToken().type; - - if (type === lexer.TOKEN_RIGHT_PAREN || type === lexer.TOKEN_RIGHT_BRACKET || type === lexer.TOKEN_RIGHT_CURLY) { - this.nextToken(); - break; - } - - if (node.children.length > 0) { - if (!this.skip(lexer.TOKEN_COMMA)) { - this.fail('parseAggregate: expected comma after expression', tok.lineno, tok.colno); - } - } - - if (node instanceof nodes.Dict) { - // TODO: check for errors - var key = this.parsePrimary(); // We expect a key/value pair for dicts, separated by a - // colon - - if (!this.skip(lexer.TOKEN_COLON)) { - this.fail('parseAggregate: expected colon after dict key', tok.lineno, tok.colno); - } // TODO: check for errors - - - var value = this.parseExpression(); - node.addChild(new nodes.Pair(key.lineno, key.colno, key, value)); - } else { - // TODO: check for errors - var expr = this.parseExpression(); - node.addChild(expr); - } - } - - return node; - }; - - _proto.parseSignature = function parseSignature(tolerant, noParens) { - var tok = this.peekToken(); - - if (!noParens && tok.type !== lexer.TOKEN_LEFT_PAREN) { - if (tolerant) { - return null; - } else { - this.fail('expected arguments', tok.lineno, tok.colno); - } - } - - if (tok.type === lexer.TOKEN_LEFT_PAREN) { - tok = this.nextToken(); - } - - var args = new nodes.NodeList(tok.lineno, tok.colno); - var kwargs = new nodes.KeywordArgs(tok.lineno, tok.colno); - var checkComma = false; - - while (1) { - // eslint-disable-line no-constant-condition - tok = this.peekToken(); - - if (!noParens && tok.type === lexer.TOKEN_RIGHT_PAREN) { - this.nextToken(); - break; - } else if (noParens && tok.type === lexer.TOKEN_BLOCK_END) { - break; - } - - if (checkComma && !this.skip(lexer.TOKEN_COMMA)) { - this.fail('parseSignature: expected comma after expression', tok.lineno, tok.colno); - } else { - var arg = this.parseExpression(); - - if (this.skipValue(lexer.TOKEN_OPERATOR, '=')) { - kwargs.addChild(new nodes.Pair(arg.lineno, arg.colno, arg, this.parseExpression())); - } else { - args.addChild(arg); - } - } - - checkComma = true; - } - - if (kwargs.children.length) { - args.addChild(kwargs); - } - - return args; - }; - - _proto.parseUntilBlocks = function parseUntilBlocks() { - var prev = this.breakOnBlocks; - - for (var _len = arguments.length, blockNames = new Array(_len), _key = 0; _key < _len; _key++) { - blockNames[_key] = arguments[_key]; - } - - this.breakOnBlocks = blockNames; - var ret = this.parse(); - this.breakOnBlocks = prev; - return ret; - }; - - _proto.parseNodes = function parseNodes() { - var tok; - var buf = []; - - while (tok = this.nextToken()) { - if (tok.type === lexer.TOKEN_DATA) { - var data = tok.value; - var nextToken = this.peekToken(); - var nextVal = nextToken && nextToken.value; // If the last token has "-" we need to trim the - // leading whitespace of the data. This is marked with - // the `dropLeadingWhitespace` variable. - - if (this.dropLeadingWhitespace) { - // TODO: this could be optimized (don't use regex) - data = data.replace(/^\s*/, ''); - this.dropLeadingWhitespace = false; - } // Same for the succeeding block start token - - - if (nextToken && (nextToken.type === lexer.TOKEN_BLOCK_START && nextVal.charAt(nextVal.length - 1) === '-' || nextToken.type === lexer.TOKEN_VARIABLE_START && nextVal.charAt(this.tokens.tags.VARIABLE_START.length) === '-' || nextToken.type === lexer.TOKEN_COMMENT && nextVal.charAt(this.tokens.tags.COMMENT_START.length) === '-')) { - // TODO: this could be optimized (don't use regex) - data = data.replace(/\s*$/, ''); - } - - buf.push(new nodes.Output(tok.lineno, tok.colno, [new nodes.TemplateData(tok.lineno, tok.colno, data)])); - } else if (tok.type === lexer.TOKEN_BLOCK_START) { - this.dropLeadingWhitespace = false; - var n = this.parseStatement(); - - if (!n) { - break; - } - - buf.push(n); - } else if (tok.type === lexer.TOKEN_VARIABLE_START) { - var e = this.parseExpression(); - this.dropLeadingWhitespace = false; - this.advanceAfterVariableEnd(); - buf.push(new nodes.Output(tok.lineno, tok.colno, [e])); - } else if (tok.type === lexer.TOKEN_COMMENT) { - this.dropLeadingWhitespace = tok.value.charAt(tok.value.length - this.tokens.tags.COMMENT_END.length - 1) === '-'; - } else { - // Ignore comments, otherwise this should be an error - this.fail('Unexpected token at top-level: ' + tok.type, tok.lineno, tok.colno); - } - } - - return buf; - }; - - _proto.parse = function parse() { - return new nodes.NodeList(0, 0, this.parseNodes()); - }; - - _proto.parseAsRoot = function parseAsRoot() { - return new nodes.Root(0, 0, this.parseNodes()); - }; - - return Parser; -}(Obj); // var util = require('util'); -// var l = lexer.lex('{%- if x -%}\n hello {% endif %}'); -// var t; -// while((t = l.nextToken())) { -// console.log(util.inspect(t)); -// } -// var p = new Parser(lexer.lex('hello {% filter title %}' + -// 'Hello madam how are you' + -// '{% endfilter %}')); -// var n = p.parseAsRoot(); -// nodes.printNodes(n); - - -module.exports = { - parse: function parse(src, extensions, opts) { - var p = new Parser(lexer.lex(src, opts)); - - if (extensions !== undefined) { - p.extensions = extensions; - } - - return p.parseAsRoot(); - }, - Parser: Parser -}; - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var lib = __webpack_require__(0); - -var whitespaceChars = " \n\t\r\xA0"; -var delimChars = '()[]{}%*-+~/#,:|.<>=!'; -var intChars = '0123456789'; -var BLOCK_START = '{%'; -var BLOCK_END = '%}'; -var VARIABLE_START = '{{'; -var VARIABLE_END = '}}'; -var COMMENT_START = '{#'; -var COMMENT_END = '#}'; -var TOKEN_STRING = 'string'; -var TOKEN_WHITESPACE = 'whitespace'; -var TOKEN_DATA = 'data'; -var TOKEN_BLOCK_START = 'block-start'; -var TOKEN_BLOCK_END = 'block-end'; -var TOKEN_VARIABLE_START = 'variable-start'; -var TOKEN_VARIABLE_END = 'variable-end'; -var TOKEN_COMMENT = 'comment'; -var TOKEN_LEFT_PAREN = 'left-paren'; -var TOKEN_RIGHT_PAREN = 'right-paren'; -var TOKEN_LEFT_BRACKET = 'left-bracket'; -var TOKEN_RIGHT_BRACKET = 'right-bracket'; -var TOKEN_LEFT_CURLY = 'left-curly'; -var TOKEN_RIGHT_CURLY = 'right-curly'; -var TOKEN_OPERATOR = 'operator'; -var TOKEN_COMMA = 'comma'; -var TOKEN_COLON = 'colon'; -var TOKEN_TILDE = 'tilde'; -var TOKEN_PIPE = 'pipe'; -var TOKEN_INT = 'int'; -var TOKEN_FLOAT = 'float'; -var TOKEN_BOOLEAN = 'boolean'; -var TOKEN_NONE = 'none'; -var TOKEN_SYMBOL = 'symbol'; -var TOKEN_SPECIAL = 'special'; -var TOKEN_REGEX = 'regex'; - -function token(type, value, lineno, colno) { - return { - type: type, - value: value, - lineno: lineno, - colno: colno - }; -} - -var Tokenizer = -/*#__PURE__*/ -function () { - function Tokenizer(str, opts) { - this.str = str; - this.index = 0; - this.len = str.length; - this.lineno = 0; - this.colno = 0; - this.in_code = false; - opts = opts || {}; - var tags = opts.tags || {}; - this.tags = { - BLOCK_START: tags.blockStart || BLOCK_START, - BLOCK_END: tags.blockEnd || BLOCK_END, - VARIABLE_START: tags.variableStart || VARIABLE_START, - VARIABLE_END: tags.variableEnd || VARIABLE_END, - COMMENT_START: tags.commentStart || COMMENT_START, - COMMENT_END: tags.commentEnd || COMMENT_END - }; - this.trimBlocks = !!opts.trimBlocks; - this.lstripBlocks = !!opts.lstripBlocks; - } - - var _proto = Tokenizer.prototype; - - _proto.nextToken = function nextToken() { - var lineno = this.lineno; - var colno = this.colno; - var tok; - - if (this.in_code) { - // Otherwise, if we are in a block parse it as code - var cur = this.current(); - - if (this.isFinished()) { - // We have nothing else to parse - return null; - } else if (cur === '"' || cur === '\'') { - // We've hit a string - return token(TOKEN_STRING, this._parseString(cur), lineno, colno); - } else if (tok = this._extract(whitespaceChars)) { - // We hit some whitespace - return token(TOKEN_WHITESPACE, tok, lineno, colno); - } else if ((tok = this._extractString(this.tags.BLOCK_END)) || (tok = this._extractString('-' + this.tags.BLOCK_END))) { - // Special check for the block end tag - // - // It is a requirement that start and end tags are composed of - // delimiter characters (%{}[] etc), and our code always - // breaks on delimiters so we can assume the token parsing - // doesn't consume these elsewhere - this.in_code = false; - - if (this.trimBlocks) { - cur = this.current(); - - if (cur === '\n') { - // Skip newline - this.forward(); - } else if (cur === '\r') { - // Skip CRLF newline - this.forward(); - cur = this.current(); - - if (cur === '\n') { - this.forward(); - } else { - // Was not a CRLF, so go back - this.back(); - } - } - } - - return token(TOKEN_BLOCK_END, tok, lineno, colno); - } else if ((tok = this._extractString(this.tags.VARIABLE_END)) || (tok = this._extractString('-' + this.tags.VARIABLE_END))) { - // Special check for variable end tag (see above) - this.in_code = false; - return token(TOKEN_VARIABLE_END, tok, lineno, colno); - } else if (cur === 'r' && this.str.charAt(this.index + 1) === '/') { - // Skip past 'r/'. - this.forwardN(2); // Extract until the end of the regex -- / ends it, \/ does not. - - var regexBody = ''; - - while (!this.isFinished()) { - if (this.current() === '/' && this.previous() !== '\\') { - this.forward(); - break; - } else { - regexBody += this.current(); - this.forward(); - } - } // Check for flags. - // The possible flags are according to https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/RegExp) - - - var POSSIBLE_FLAGS = ['g', 'i', 'm', 'y']; - var regexFlags = ''; - - while (!this.isFinished()) { - var isCurrentAFlag = POSSIBLE_FLAGS.indexOf(this.current()) !== -1; - - if (isCurrentAFlag) { - regexFlags += this.current(); - this.forward(); - } else { - break; - } - } - - return token(TOKEN_REGEX, { - body: regexBody, - flags: regexFlags - }, lineno, colno); - } else if (delimChars.indexOf(cur) !== -1) { - // We've hit a delimiter (a special char like a bracket) - this.forward(); - var complexOps = ['==', '===', '!=', '!==', '<=', '>=', '//', '**']; - var curComplex = cur + this.current(); - var type; - - if (lib.indexOf(complexOps, curComplex) !== -1) { - this.forward(); - cur = curComplex; // See if this is a strict equality/inequality comparator - - if (lib.indexOf(complexOps, curComplex + this.current()) !== -1) { - cur = curComplex + this.current(); - this.forward(); - } - } - - switch (cur) { - case '(': - type = TOKEN_LEFT_PAREN; - break; - - case ')': - type = TOKEN_RIGHT_PAREN; - break; - - case '[': - type = TOKEN_LEFT_BRACKET; - break; - - case ']': - type = TOKEN_RIGHT_BRACKET; - break; - - case '{': - type = TOKEN_LEFT_CURLY; - break; - - case '}': - type = TOKEN_RIGHT_CURLY; - break; - - case ',': - type = TOKEN_COMMA; - break; - - case ':': - type = TOKEN_COLON; - break; - - case '~': - type = TOKEN_TILDE; - break; - - case '|': - type = TOKEN_PIPE; - break; - - default: - type = TOKEN_OPERATOR; - } - - return token(type, cur, lineno, colno); - } else { - // We are not at whitespace or a delimiter, so extract the - // text and parse it - tok = this._extractUntil(whitespaceChars + delimChars); - - if (tok.match(/^[-+]?[0-9]+$/)) { - if (this.current() === '.') { - this.forward(); - - var dec = this._extract(intChars); - - return token(TOKEN_FLOAT, tok + '.' + dec, lineno, colno); - } else { - return token(TOKEN_INT, tok, lineno, colno); - } - } else if (tok.match(/^(true|false)$/)) { - return token(TOKEN_BOOLEAN, tok, lineno, colno); - } else if (tok === 'none') { - return token(TOKEN_NONE, tok, lineno, colno); - /* - * Added to make the test `null is null` evaluate truthily. - * Otherwise, Nunjucks will look up null in the context and - * return `undefined`, which is not what we want. This *may* have - * consequences is someone is using null in their templates as a - * variable. - */ - } else if (tok === 'null') { - return token(TOKEN_NONE, tok, lineno, colno); - } else if (tok) { - return token(TOKEN_SYMBOL, tok, lineno, colno); - } else { - throw new Error('Unexpected value while parsing: ' + tok); - } - } - } else { - // Parse out the template text, breaking on tag - // delimiters because we need to look for block/variable start - // tags (don't use the full delimChars for optimization) - var beginChars = this.tags.BLOCK_START.charAt(0) + this.tags.VARIABLE_START.charAt(0) + this.tags.COMMENT_START.charAt(0) + this.tags.COMMENT_END.charAt(0); - - if (this.isFinished()) { - return null; - } else if ((tok = this._extractString(this.tags.BLOCK_START + '-')) || (tok = this._extractString(this.tags.BLOCK_START))) { - this.in_code = true; - return token(TOKEN_BLOCK_START, tok, lineno, colno); - } else if ((tok = this._extractString(this.tags.VARIABLE_START + '-')) || (tok = this._extractString(this.tags.VARIABLE_START))) { - this.in_code = true; - return token(TOKEN_VARIABLE_START, tok, lineno, colno); - } else { - tok = ''; - var data; - var inComment = false; - - if (this._matches(this.tags.COMMENT_START)) { - inComment = true; - tok = this._extractString(this.tags.COMMENT_START); - } // Continually consume text, breaking on the tag delimiter - // characters and checking to see if it's a start tag. - // - // We could hit the end of the template in the middle of - // our looping, so check for the null return value from - // _extractUntil - - - while ((data = this._extractUntil(beginChars)) !== null) { - tok += data; - - if ((this._matches(this.tags.BLOCK_START) || this._matches(this.tags.VARIABLE_START) || this._matches(this.tags.COMMENT_START)) && !inComment) { - if (this.lstripBlocks && this._matches(this.tags.BLOCK_START) && this.colno > 0 && this.colno <= tok.length) { - var lastLine = tok.slice(-this.colno); - - if (/^\s+$/.test(lastLine)) { - // Remove block leading whitespace from beginning of the string - tok = tok.slice(0, -this.colno); - - if (!tok.length) { - // All data removed, collapse to avoid unnecessary nodes - // by returning next token (block start) - return this.nextToken(); - } - } - } // If it is a start tag, stop looping - - - break; - } else if (this._matches(this.tags.COMMENT_END)) { - if (!inComment) { - throw new Error('unexpected end of comment'); - } - - tok += this._extractString(this.tags.COMMENT_END); - break; - } else { - // It does not match any tag, so add the character and - // carry on - tok += this.current(); - this.forward(); - } - } - - if (data === null && inComment) { - throw new Error('expected end of comment, got end of file'); - } - - return token(inComment ? TOKEN_COMMENT : TOKEN_DATA, tok, lineno, colno); - } - } - }; - - _proto._parseString = function _parseString(delimiter) { - this.forward(); - var str = ''; - - while (!this.isFinished() && this.current() !== delimiter) { - var cur = this.current(); - - if (cur === '\\') { - this.forward(); - - switch (this.current()) { - case 'n': - str += '\n'; - break; - - case 't': - str += '\t'; - break; - - case 'r': - str += '\r'; - break; - - default: - str += this.current(); - } - - this.forward(); - } else { - str += cur; - this.forward(); - } - } - - this.forward(); - return str; - }; - - _proto._matches = function _matches(str) { - if (this.index + str.length > this.len) { - return null; - } - - var m = this.str.slice(this.index, this.index + str.length); - return m === str; - }; - - _proto._extractString = function _extractString(str) { - if (this._matches(str)) { - this.forwardN(str.length); - return str; - } - - return null; - }; - - _proto._extractUntil = function _extractUntil(charString) { - // Extract all non-matching chars, with the default matching set - // to everything - return this._extractMatching(true, charString || ''); - }; - - _proto._extract = function _extract(charString) { - // Extract all matching chars (no default, so charString must be - // explicit) - return this._extractMatching(false, charString); - }; - - _proto._extractMatching = function _extractMatching(breakOnMatch, charString) { - // Pull out characters until a breaking char is hit. - // If breakOnMatch is false, a non-matching char stops it. - // If breakOnMatch is true, a matching char stops it. - if (this.isFinished()) { - return null; - } - - var first = charString.indexOf(this.current()); // Only proceed if the first character doesn't meet our condition - - if (breakOnMatch && first === -1 || !breakOnMatch && first !== -1) { - var t = this.current(); - this.forward(); // And pull out all the chars one at a time until we hit a - // breaking char - - var idx = charString.indexOf(this.current()); - - while ((breakOnMatch && idx === -1 || !breakOnMatch && idx !== -1) && !this.isFinished()) { - t += this.current(); - this.forward(); - idx = charString.indexOf(this.current()); - } - - return t; - } - - return ''; - }; - - _proto._extractRegex = function _extractRegex(regex) { - var matches = this.currentStr().match(regex); - - if (!matches) { - return null; - } // Move forward whatever was matched - - - this.forwardN(matches[0].length); - return matches; - }; - - _proto.isFinished = function isFinished() { - return this.index >= this.len; - }; - - _proto.forwardN = function forwardN(n) { - for (var i = 0; i < n; i++) { - this.forward(); - } - }; - - _proto.forward = function forward() { - this.index++; - - if (this.previous() === '\n') { - this.lineno++; - this.colno = 0; - } else { - this.colno++; - } - }; - - _proto.backN = function backN(n) { - for (var i = 0; i < n; i++) { - this.back(); - } - }; - - _proto.back = function back() { - this.index--; - - if (this.current() === '\n') { - this.lineno--; - var idx = this.src.lastIndexOf('\n', this.index - 1); - - if (idx === -1) { - this.colno = this.index; - } else { - this.colno = this.index - idx; - } - } else { - this.colno--; - } - }; // current returns current character - - - _proto.current = function current() { - if (!this.isFinished()) { - return this.str.charAt(this.index); - } - - return ''; - }; // currentStr returns what's left of the unparsed string - - - _proto.currentStr = function currentStr() { - if (!this.isFinished()) { - return this.str.substr(this.index); - } - - return ''; - }; - - _proto.previous = function previous() { - return this.str.charAt(this.index - 1); - }; - - return Tokenizer; -}(); - -module.exports = { - lex: function lex(src, opts) { - return new Tokenizer(src, opts); - }, - TOKEN_STRING: TOKEN_STRING, - TOKEN_WHITESPACE: TOKEN_WHITESPACE, - TOKEN_DATA: TOKEN_DATA, - TOKEN_BLOCK_START: TOKEN_BLOCK_START, - TOKEN_BLOCK_END: TOKEN_BLOCK_END, - TOKEN_VARIABLE_START: TOKEN_VARIABLE_START, - TOKEN_VARIABLE_END: TOKEN_VARIABLE_END, - TOKEN_COMMENT: TOKEN_COMMENT, - TOKEN_LEFT_PAREN: TOKEN_LEFT_PAREN, - TOKEN_RIGHT_PAREN: TOKEN_RIGHT_PAREN, - TOKEN_LEFT_BRACKET: TOKEN_LEFT_BRACKET, - TOKEN_RIGHT_BRACKET: TOKEN_RIGHT_BRACKET, - TOKEN_LEFT_CURLY: TOKEN_LEFT_CURLY, - TOKEN_RIGHT_CURLY: TOKEN_RIGHT_CURLY, - TOKEN_OPERATOR: TOKEN_OPERATOR, - TOKEN_COMMA: TOKEN_COMMA, - TOKEN_COLON: TOKEN_COLON, - TOKEN_TILDE: TOKEN_TILDE, - TOKEN_PIPE: TOKEN_PIPE, - TOKEN_INT: TOKEN_INT, - TOKEN_FLOAT: TOKEN_FLOAT, - TOKEN_BOOLEAN: TOKEN_BOOLEAN, - TOKEN_NONE: TOKEN_NONE, - TOKEN_SYMBOL: TOKEN_SYMBOL, - TOKEN_SPECIAL: TOKEN_SPECIAL, - TOKEN_REGEX: TOKEN_REGEX -}; - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } - -var Loader = __webpack_require__(6); - -var _require = __webpack_require__(19), - PrecompiledLoader = _require.PrecompiledLoader; - -var WebLoader = -/*#__PURE__*/ -function (_Loader) { - _inheritsLoose(WebLoader, _Loader); - - function WebLoader(baseURL, opts) { - var _this; - - _this = _Loader.call(this) || this; - _this.baseURL = baseURL || '.'; - opts = opts || {}; // By default, the cache is turned off because there's no way - // to "watch" templates over HTTP, so they are re-downloaded - // and compiled each time. (Remember, PRECOMPILE YOUR - // TEMPLATES in production!) - - _this.useCache = !!opts.useCache; // We default `async` to false so that the simple synchronous - // API can be used when you aren't doing anything async in - // your templates (which is most of the time). This performs a - // sync ajax request, but that's ok because it should *only* - // happen in development. PRECOMPILE YOUR TEMPLATES. - - _this.async = !!opts.async; - return _this; - } - - var _proto = WebLoader.prototype; - - _proto.resolve = function resolve(from, to) { - throw new Error('relative templates not support in the browser yet'); - }; - - _proto.getSource = function getSource(name, cb) { - var _this2 = this; - - var useCache = this.useCache; - var result; - this.fetch(this.baseURL + '/' + name, function (err, src) { - if (err) { - if (cb) { - cb(err.content); - } else if (err.status === 404) { - result = null; - } else { - throw err.content; - } - } else { - result = { - src: src, - path: name, - noCache: !useCache - }; - - _this2.emit('load', name, result); - - if (cb) { - cb(null, result); - } - } - }); // if this WebLoader isn't running asynchronously, the - // fetch above would actually run sync and we'll have a - // result here - - return result; - }; - - _proto.fetch = function fetch(url, cb) { - // Only in the browser please - if (typeof window === 'undefined') { - throw new Error('WebLoader can only by used in a browser'); - } - - var ajax = new XMLHttpRequest(); - var loading = true; - - ajax.onreadystatechange = function () { - if (ajax.readyState === 4 && loading) { - loading = false; - - if (ajax.status === 0 || ajax.status === 200) { - cb(null, ajax.responseText); - } else { - cb({ - status: ajax.status, - content: ajax.responseText - }); - } - } - }; - - url += (url.indexOf('?') === -1 ? '?' : '&') + 's=' + new Date().getTime(); - ajax.open('GET', url, this.async); - ajax.send(); - }; - - return WebLoader; -}(Loader); - -module.exports = { - WebLoader: WebLoader, - PrecompiledLoader: PrecompiledLoader -}; - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var lib = __webpack_require__(0); - -var _require = __webpack_require__(7), - Environment = _require.Environment, - Template = _require.Template; - -var Loader = __webpack_require__(6); - -var loaders = __webpack_require__(10); - -var precompile = __webpack_require__(23); - -var compiler = __webpack_require__(5); - -var parser = __webpack_require__(8); - -var lexer = __webpack_require__(9); - -var runtime = __webpack_require__(2); - -var nodes = __webpack_require__(3); - -var installJinjaCompat = __webpack_require__(25); // A single instance of an environment, since this is so commonly used - - -var e; - -function configure(templatesPath, opts) { - opts = opts || {}; - - if (lib.isObject(templatesPath)) { - opts = templatesPath; - templatesPath = null; - } - - var TemplateLoader; - - if (loaders.FileSystemLoader) { - TemplateLoader = new loaders.FileSystemLoader(templatesPath, { - watch: opts.watch, - noCache: opts.noCache - }); - } else if (loaders.WebLoader) { - TemplateLoader = new loaders.WebLoader(templatesPath, { - useCache: opts.web && opts.web.useCache, - async: opts.web && opts.web.async - }); - } - - e = new Environment(TemplateLoader, opts); - - if (opts && opts.express) { - e.express(opts.express); - } - - return e; -} - -module.exports = { - Environment: Environment, - Template: Template, - Loader: Loader, - FileSystemLoader: loaders.FileSystemLoader, - NodeResolveLoader: loaders.NodeResolveLoader, - PrecompiledLoader: loaders.PrecompiledLoader, - WebLoader: loaders.WebLoader, - compiler: compiler, - parser: parser, - lexer: lexer, - runtime: runtime, - lib: lib, - nodes: nodes, - installJinjaCompat: installJinjaCompat, - configure: configure, - reset: function reset() { - e = undefined; - }, - compile: function compile(src, env, path, eagerCompile) { - if (!e) { - configure(); - } - - return new Template(src, env, path, eagerCompile); - }, - render: function render(name, ctx, cb) { - if (!e) { - configure(); - } - - return e.render(name, ctx, cb); - }, - renderString: function renderString(src, ctx, cb) { - if (!e) { - configure(); - } - - return e.renderString(src, ctx, cb); - }, - precompile: precompile ? precompile.precompile : undefined, - precompileString: precompile ? precompile.precompileString : undefined -}; - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -// rawAsap provides everything we need except exception management. -var rawAsap = __webpack_require__(13); -// RawTasks are recycled to reduce GC churn. -var freeTasks = []; -// We queue errors to ensure they are thrown in right order (FIFO). -// Array-as-queue is good enough here, since we are just dealing with exceptions. -var pendingErrors = []; -var requestErrorThrow = rawAsap.makeRequestCallFromTimer(throwFirstError); - -function throwFirstError() { - if (pendingErrors.length) { - throw pendingErrors.shift(); - } -} - -/** - * Calls a task as soon as possible after returning, in its own event, with priority - * over other events like animation, reflow, and repaint. An error thrown from an - * event will not interrupt, nor even substantially slow down the processing of - * other events, but will be rather postponed to a lower priority event. - * @param {{call}} task A callable object, typically a function that takes no - * arguments. - */ -module.exports = asap; -function asap(task) { - var rawTask; - if (freeTasks.length) { - rawTask = freeTasks.pop(); - } else { - rawTask = new RawTask(); - } - rawTask.task = task; - rawAsap(rawTask); -} - -// We wrap tasks with recyclable task objects. A task object implements -// `call`, just like a function. -function RawTask() { - this.task = null; -} - -// The sole purpose of wrapping the task is to catch the exception and recycle -// the task object after its single use. -RawTask.prototype.call = function () { - try { - this.task.call(); - } catch (error) { - if (asap.onerror) { - // This hook exists purely for testing purposes. - // Its name will be periodically randomized to break any code that - // depends on its existence. - asap.onerror(error); - } else { - // In a web browser, exceptions are not fatal. However, to avoid - // slowing down the queue of pending tasks, we rethrow the error in a - // lower priority turn. - pendingErrors.push(error); - requestErrorThrow(); - } - } finally { - this.task = null; - freeTasks[freeTasks.length] = this; - } -}; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(global) { - -// Use the fastest means possible to execute a task in its own turn, with -// priority over other events including IO, animation, reflow, and redraw -// events in browsers. -// -// An exception thrown by a task will permanently interrupt the processing of -// subsequent tasks. The higher level `asap` function ensures that if an -// exception is thrown by a task, that the task queue will continue flushing as -// soon as possible, but if you use `rawAsap` directly, you are responsible to -// either ensure that no exceptions are thrown from your task, or to manually -// call `rawAsap.requestFlush` if an exception is thrown. -module.exports = rawAsap; -function rawAsap(task) { - if (!queue.length) { - requestFlush(); - flushing = true; - } - // Equivalent to push, but avoids a function call. - queue[queue.length] = task; -} - -var queue = []; -// Once a flush has been requested, no further calls to `requestFlush` are -// necessary until the next `flush` completes. -var flushing = false; -// `requestFlush` is an implementation-specific method that attempts to kick -// off a `flush` event as quickly as possible. `flush` will attempt to exhaust -// the event queue before yielding to the browser's own event loop. -var requestFlush; -// The position of the next task to execute in the task queue. This is -// preserved between calls to `flush` so that it can be resumed if -// a task throws an exception. -var index = 0; -// If a task schedules additional tasks recursively, the task queue can grow -// unbounded. To prevent memory exhaustion, the task queue will periodically -// truncate already-completed tasks. -var capacity = 1024; - -// The flush function processes all tasks that have been scheduled with -// `rawAsap` unless and until one of those tasks throws an exception. -// If a task throws an exception, `flush` ensures that its state will remain -// consistent and will resume where it left off when called again. -// However, `flush` does not make any arrangements to be called again if an -// exception is thrown. -function flush() { - while (index < queue.length) { - var currentIndex = index; - // Advance the index before calling the task. This ensures that we will - // begin flushing on the next task the task throws an error. - index = index + 1; - queue[currentIndex].call(); - // Prevent leaking memory for long chains of recursive calls to `asap`. - // If we call `asap` within tasks scheduled by `asap`, the queue will - // grow, but to avoid an O(n) walk for every task we execute, we don't - // shift tasks off the queue after they have been executed. - // Instead, we periodically shift 1024 tasks off the queue. - if (index > capacity) { - // Manually shift all values starting at the index back to the - // beginning of the queue. - for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) { - queue[scan] = queue[scan + index]; - } - queue.length -= index; - index = 0; - } - } - queue.length = 0; - index = 0; - flushing = false; -} - -// `requestFlush` is implemented using a strategy based on data collected from -// every available SauceLabs Selenium web driver worker at time of writing. -// https://docs.google.com/spreadsheets/d/1mG-5UYGup5qxGdEMWkhP6BWCz053NUb2E1QoUTU16uA/edit#gid=783724593 - -// Safari 6 and 6.1 for desktop, iPad, and iPhone are the only browsers that -// have WebKitMutationObserver but not un-prefixed MutationObserver. -// Must use `global` or `self` instead of `window` to work in both frames and web -// workers. `global` is a provision of Browserify, Mr, Mrs, or Mop. - -/* globals self */ -var scope = typeof global !== "undefined" ? global : self; -var BrowserMutationObserver = scope.MutationObserver || scope.WebKitMutationObserver; - -// MutationObservers are desirable because they have high priority and work -// reliably everywhere they are implemented. -// They are implemented in all modern browsers. -// -// - Android 4-4.3 -// - Chrome 26-34 -// - Firefox 14-29 -// - Internet Explorer 11 -// - iPad Safari 6-7.1 -// - iPhone Safari 7-7.1 -// - Safari 6-7 -if (typeof BrowserMutationObserver === "function") { - requestFlush = makeRequestCallFromMutationObserver(flush); - -// MessageChannels are desirable because they give direct access to the HTML -// task queue, are implemented in Internet Explorer 10, Safari 5.0-1, and Opera -// 11-12, and in web workers in many engines. -// Although message channels yield to any queued rendering and IO tasks, they -// would be better than imposing the 4ms delay of timers. -// However, they do not work reliably in Internet Explorer or Safari. - -// Internet Explorer 10 is the only browser that has setImmediate but does -// not have MutationObservers. -// Although setImmediate yields to the browser's renderer, it would be -// preferrable to falling back to setTimeout since it does not have -// the minimum 4ms penalty. -// Unfortunately there appears to be a bug in Internet Explorer 10 Mobile (and -// Desktop to a lesser extent) that renders both setImmediate and -// MessageChannel useless for the purposes of ASAP. -// https://github.com/kriskowal/q/issues/396 - -// Timers are implemented universally. -// We fall back to timers in workers in most engines, and in foreground -// contexts in the following browsers. -// However, note that even this simple case requires nuances to operate in a -// broad spectrum of browsers. -// -// - Firefox 3-13 -// - Internet Explorer 6-9 -// - iPad Safari 4.3 -// - Lynx 2.8.7 -} else { - requestFlush = makeRequestCallFromTimer(flush); -} - -// `requestFlush` requests that the high priority event queue be flushed as -// soon as possible. -// This is useful to prevent an error thrown in a task from stalling the event -// queue if the exception handled by Node.js’s -// `process.on("uncaughtException")` or by a domain. -rawAsap.requestFlush = requestFlush; - -// To request a high priority event, we induce a mutation observer by toggling -// the text of a text node between "1" and "-1". -function makeRequestCallFromMutationObserver(callback) { - var toggle = 1; - var observer = new BrowserMutationObserver(callback); - var node = document.createTextNode(""); - observer.observe(node, {characterData: true}); - return function requestCall() { - toggle = -toggle; - node.data = toggle; - }; -} - -// The message channel technique was discovered by Malte Ubl and was the -// original foundation for this library. -// http://www.nonblocking.io/2011/06/windownexttick.html - -// Safari 6.0.5 (at least) intermittently fails to create message ports on a -// page's first load. Thankfully, this version of Safari supports -// MutationObservers, so we don't need to fall back in that case. - -// function makeRequestCallFromMessageChannel(callback) { -// var channel = new MessageChannel(); -// channel.port1.onmessage = callback; -// return function requestCall() { -// channel.port2.postMessage(0); -// }; -// } - -// For reasons explained above, we are also unable to use `setImmediate` -// under any circumstances. -// Even if we were, there is another bug in Internet Explorer 10. -// It is not sufficient to assign `setImmediate` to `requestFlush` because -// `setImmediate` must be called *by name* and therefore must be wrapped in a -// closure. -// Never forget. - -// function makeRequestCallFromSetImmediate(callback) { -// return function requestCall() { -// setImmediate(callback); -// }; -// } - -// Safari 6.0 has a problem where timers will get lost while the user is -// scrolling. This problem does not impact ASAP because Safari 6.0 supports -// mutation observers, so that implementation is used instead. -// However, if we ever elect to use timers in Safari, the prevalent work-around -// is to add a scroll event listener that calls for a flush. - -// `setTimeout` does not call the passed callback if the delay is less than -// approximately 7 in web workers in Firefox 8 through 18, and sometimes not -// even then. - -function makeRequestCallFromTimer(callback) { - return function requestCall() { - // We dispatch a timeout with a specified delay of 0 for engines that - // can reliably accommodate that request. This will usually be snapped - // to a 4 milisecond delay, but once we're flushing, there's no delay - // between events. - var timeoutHandle = setTimeout(handleTimer, 0); - // However, since this timer gets frequently dropped in Firefox - // workers, we enlist an interval handle that will try to fire - // an event 20 times per second until it succeeds. - var intervalHandle = setInterval(handleTimer, 50); - - function handleTimer() { - // Whichever timer succeeds will cancel both timers and - // execute the callback. - clearTimeout(timeoutHandle); - clearInterval(intervalHandle); - callback(); - } - }; -} - -// This is for `asap.js` only. -// Its name will be periodically randomized to break any code that depends on -// its existence. -rawAsap.makeRequestCallFromTimer = makeRequestCallFromTimer; - -// ASAP was originally a nextTick shim included in Q. This was factored out -// into this ASAP package. It was later adapted to RSVP which made further -// amendments. These decisions, particularly to marginalize MessageChannel and -// to capture the MutationObserver implementation in a closure, were integrated -// back into ASAP proper. -// https://github.com/tildeio/rsvp.js/blob/cddf7232546a9cf858524b75cde6f9edf72620a7/lib/rsvp/asap.js - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(14))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports) { - -var g; - -// This works in non-strict mode -g = (function() { - return this; -})(); - -try { - // This works if eval is allowed (see CSP) - g = g || Function("return this")() || (1,eval)("this"); -} catch(e) { - // This works if the window reference is available - if(typeof window === "object") - g = window; -} - -// g can still be undefined, but nothing to do about it... -// We return undefined, instead of nothing here, so it's -// easier to handle this case. if(!global) { ...} - -module.exports = g; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;// MIT license (by Elan Shanker). -(function(globals) { - 'use strict'; - - var executeSync = function(){ - var args = Array.prototype.slice.call(arguments); - if (typeof args[0] === 'function'){ - args[0].apply(null, args.splice(1)); - } - }; - - var executeAsync = function(fn){ - if (typeof setImmediate === 'function') { - setImmediate(fn); - } else if (typeof process !== 'undefined' && process.nextTick) { - process.nextTick(fn); - } else { - setTimeout(fn, 0); - } - }; - - var makeIterator = function (tasks) { - var makeCallback = function (index) { - var fn = function () { - if (tasks.length) { - tasks[index].apply(null, arguments); - } - return fn.next(); - }; - fn.next = function () { - return (index < tasks.length - 1) ? makeCallback(index + 1): null; - }; - return fn; - }; - return makeCallback(0); - }; - - var _isArray = Array.isArray || function(maybeArray){ - return Object.prototype.toString.call(maybeArray) === '[object Array]'; - }; - - var waterfall = function (tasks, callback, forceAsync) { - var nextTick = forceAsync ? executeAsync : executeSync; - callback = callback || function () {}; - if (!_isArray(tasks)) { - var err = new Error('First argument to waterfall must be an array of functions'); - return callback(err); - } - if (!tasks.length) { - return callback(); - } - var wrapIterator = function (iterator) { - return function (err) { - if (err) { - callback.apply(null, arguments); - callback = function () {}; - } else { - var args = Array.prototype.slice.call(arguments, 1); - var next = iterator.next(); - if (next) { - args.push(wrapIterator(next)); - } else { - args.push(callback); - } - nextTick(function () { - iterator.apply(null, args); - }); - } - }; - }; - wrapIterator(makeIterator(tasks))(); - }; - - if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = (function () { - return waterfall; - }).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); // RequireJS - } else if (typeof module !== 'undefined' && module.exports) { - module.exports = waterfall; // CommonJS - } else { - globals.waterfall = waterfall; // - - - - -# Package `eido` Documentation - - -Project configuration - -```python -def basic_pep_filter(p, **kwargs) -> Dict[str, str] -``` - -Basic PEP filter, that does not convert the Project object. - -This filter can save the PEP representation to file, if kwargs include `path`. -#### Parameters: - -- `p` (`peppy.Project`): a Project to run filter on - - - - -```python -def yaml_pep_filter(p, **kwargs) -> Dict[str, str] -``` - -YAML PEP filter, that returns Project object representation. - -This filter can save the YAML to file, if kwargs include `path`. -#### Parameters: - -- `p` (`peppy.Project`): a Project to run filter on - - - - -```python -def csv_pep_filter(p, **kwargs) -> Dict[str, str] -``` - -CSV PEP filter, that returns Sample object representations - -This filter can save the CSVs to files, if kwargs include -`sample_table_path` and/or `subsample_table_path`. -#### Parameters: - -- `p` (`peppy.Project`): a Project to run filter on - - - - -```python -def yaml_samples_pep_filter(p, **kwargs) -> Dict[str, str] -``` - -YAML samples PEP filter, that returns only Sample object representations. - -This filter can save the YAML to file, if kwargs include `path`. -#### Parameters: - -- `p` (`peppy.Project`): a Project to run filter on - - - - - - - -*Version Information: `eido` v0.2.2-dev, generated by `lucidoc` v0.4.4* diff --git a/docs/validator.html b/docs/validator.html deleted file mode 100644 index 67b6bc52..00000000 --- a/docs/validator.html +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - PEP web validator - - - - - - -
-

This tool will validate your sample metadata against one or more schemas. Drag and drop all parts of your PEP here. This includes metadata only, which is the config YAML file, any sample or subsample table CSV files, etc. Then, click "Validate".

-
-
-
File Upload
-
-
-
- -
-
- - - -
-
-
-
-
Results
-
- No results to display. -
-
- -

Want API access? This tool is a static, client-hosted form that accesses an API validator service based on peppy. You can also access this service programatically if you want to validate sample metadata as part of a pipeline or other tool.

- - -
- - - diff --git a/docs/writing-a-filter.md b/docs/writing-a-filter.md deleted file mode 100644 index 87f91180..00000000 --- a/docs/writing-a-filter.md +++ /dev/null @@ -1,55 +0,0 @@ -**Filters are an experimental feature and may change in feature versions of `eido`** - -# How to write a custom eido filter - -One of `eido`'s tasks is to provide a CLI to convert a PEP into alternative formats. These include some built-in formats, like `csv` (which spits out a processed `csv` file, with project/sample modified), `yaml`, and a few others. It also provides a plugin system so that you can write your own Python functions to provide custom output formats. - -## Custom filters - -To write a custom filter, start by writing a Python package. You will need to include a function that takes a `peppy.Project` object as input, and prints out the custom file format. The filter functions also can require additional keyword arguments. - -### 1. Write functions to call - -The package contain one or more functions. The filter function **must take a peppy.Project object and `**kwargs` as parameters**. Example: - -```python -import peppy - -def my_custom_filter(p, **kwargs): - import re - import sys - import yaml - - for s in p.samples: - sys.stdout.write("- ") - out = re.sub('\n', '\n ', yaml.safe_dump(s.to_dict(), default_flow_style=False)) - sys.stdout.write(out + "\n") -``` -For reference you can check the signatures of the functions in [Built-in `eido` Plugins Documentation](plugin_api_docs.md). Importantly, if the function *requires* any arguments (always provided via `**kwargs`), the creator of the function should take care of handling missing/faulty input. - -Next, we need to link that function in to the `eido` filter plugin system. - -### 2. Add entry_points to setup.py - -The `setup.py` file uses `entry_points` to specify a mapping of eido hooks to functions to call. - -```python -entry_points={ - "pep.filters": [ - "basic=eido.conversion_plugins:basic_pep_filter", - "yaml=eido.conversion_plugins:yaml_pep_filter", - "csv=eido.conversion_plugins:csv_pep_filter", - "yaml-samples=eido.conversion_plugins:yaml_samples_pep_filter", - ], -}, -``` - -The format is: `'pep.filters': 'FILTER_NAME=PLUGIN_PACKAGE_NAME:FUNCTION_NAME'`. - -- "FILTER_NAME" can be any unique identifier for your plugin -- "PLUGIN_PACKAGE_NAME" must be the name of python package the holds your plugin. -- "FUNCTION_NAME" must match the name of the function in your package - -### 3. Install package - -If you install this package, any filters provided by it will be available for use with eido, which you can see using `eido filters`. diff --git a/docs/writing-a-schema.md b/docs/writing-a-schema.md deleted file mode 100644 index 1f713629..00000000 --- a/docs/writing-a-schema.md +++ /dev/null @@ -1,124 +0,0 @@ -# How to write a PEP schema - -If you are a tool developer, we recommend you write a PEP schema that describes what sample and project attributes are required for your tool to work. PEP schemas use the [JSON Schema](https://json-schema.org/) vocabulary, plus some additional features. This guide will walk you through everything you need to know to write your own schema. It assumes you already have a basic familiarity with JSON Schema. - - -## Importing the base PEP schema - -One of the features added by `eido` is the `imports` attribute. This allows you to extend existing schemas. We recommend your new PEP schema start by importing the [base PEP schema](http://schema.databio.org/pep/2.0.0.yaml). This will ensure that the putative PEP at least follows the basic PEP specification, which you will then build on with your tool-specific requirements. Here's how we'll start with importing the generic base PEP schema: - -```yaml -description: A example schema for a pipeline. -imports: - - http://schema.databio.org/pep/2.0.0.yaml -``` - -You can also use the `imports` to build other schemas that subclass your own schemas. - -## Project and sample sections - -Like the PEP itself, the schema is divided into two sections, one for the project config, and one for the samples. So, base PEP schema defines an object with two components: a `config` object, and a `samples` array: - - -```yaml -description: A example schema for a pipeline. -imports: - - http://schema.databio.org/pep/2.0.0.yaml -properties: - config: - type: object - samples: - type: array -required: - - samples - - config -``` - - -## Required sample attributes - -Let's say you're writing a PEP-compatible tool that requires 3 arguments: `read1`, `read2`, and `genome`, and also offers optional argument `read_length`. Validating the generic PEP specification will not confirm all required attributes, so you want to write an extended schema. Starting from the base above, we're not changing the `config` section so we can drop that, and we add new parameters for the required sample attributes like this: - -```yaml -description: A example schema for a pipeline. -imports: - - http://schema.databio.org/pep/2.0.0.yaml -properties: - samples: - type: array - items: - type: object - properties: - read1: - type: string - description: "Fastq file for read 1" - read2: - type: string - description: "Fastq file for read 2" - genome: - type: string - description: "Refgenie genome registry identifier" - read_length: - type: integer - description: "Length of the Unique Molecular Identifier, if any" - required: - - read1 - - read2 - - genome -required: - - samples -``` - -This document defines the required an optional sample attributes for this pipeline. That's all you need to do, and your users can validate an existing PEP to see if it meets the requirements of your tool. - -## Required input files - -In the above example, we listed `read1` and `read2` attributes as *required*. This will enforce that these attributes must be defined on the samples, but for this example, this is not enough -- these also must *point to files that exist*. Checking for files is outside the scope of JSON Schema, which only validates JSON documents, so eido extends JSON Schema with the ability to specify which attributes should point to files. - -Eido provides two ways to do it: `files` and `required_files`. The basic `files` is simply used to specify which attributes point to files, which are not required to exist. This is useful for tools that want to calculate the total size of any provided inputs, for example. The `required_files` list specifies that the attributes point to files that *must exist*, otherwise the PEP doesn't validate. Here's an example of specifying an optional and required input attribute: - -```yaml -description: A PEP for ATAC-seq samples for the PEPATAC pipeline. -imports: - - http://schema.databio.org/pep/2.0.0.yaml -properties: - samples: - type: array - items: - type: object - properties: - sample_name: - type: string - description: "Name of the sample" - organism: - type: string - description: "Organism" - protocol: - type: string - description: "Must be an ATAC-seq or DNAse-seq sample" - genome: - type: string - description: "Refgenie genome registry identifier" - read_type: - type: string - description: "Is this single or paired-end data?" - enum: ["SINGLE", "PAIRED"] - read1: - type: string - description: "Fastq file for read 1" - read2: - type: string - description: "Fastq file for read 2 (for paired-end experiments)" - required_files: - - read1 - files: - - read1 - - read2 -``` - -This could a valid example for a pipeline that accepts either single-end or paired-end data, so `read1` must point to a file, whereas `read2` isn't required, but if it does point to a file, then this file is also to be considered an input file. - - -## Example schemas - -If you need more information, it would be a good idea to look at [example schemas](example-schemas.md) for ideas. diff --git a/docs_jupyter/build/.gitignore b/docs_jupyter/build/.gitignore deleted file mode 100644 index d6b7ef32..00000000 --- a/docs_jupyter/build/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore diff --git a/docs_jupyter/cli.ipynb b/docs_jupyter/cli.ipynb deleted file mode 100644 index 37377cbe..00000000 --- a/docs_jupyter/cli.ipynb +++ /dev/null @@ -1,407 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# `eido` command line usage" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To use the command line application one just needs a path to a project configuration file. It is a positional argument in the `eido` command.\n", - "\n", - "For this tutorial, let's grab a PEP from a public example repository that describes a few PRO-seq test samples:" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Cloning into 'ppqc'...\n", - "remote: Enumerating objects: 154, done.\u001b[K\n", - "remote: Counting objects: 100% (20/20), done.\u001b[K\n", - "remote: Compressing objects: 100% (15/15), done.\u001b[K\n", - "remote: Total 154 (delta 7), reused 17 (delta 5), pack-reused 134\u001b[K\n", - "Receiving objects: 100% (154/154), 81.69 KiB | 3.27 MiB/s, done.\n", - "Resolving deltas: 100% (82/82), done.\n" - ] - } - ], - "source": [ - "rm -rf ppqc\n", - "git clone https://github.com/databio/ppqc.git --branch cfg2" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "cd ppqc\n", - "export DATA=$HOME\n", - "export SRAFQ=$HOME" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## PEP inspection\n", - "\n", - "First, let's use `eido inspect` to inspect a PEP. \n", - "\n", - " - To inspect the entire `Project` object just provide the path to the project configuration file." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Project 'PEPPRO' (peppro_paper.yaml)\n", - "47 samples (showing first 20): K562_PRO-seq_02, K562_PRO-seq_04, K562_PRO-seq_06, K562_PRO-seq_08, K562_PRO-seq_10, K562_PRO-seq_20, K562_PRO-seq_30, K562_PRO-seq_40, K562_PRO-seq_50, K562_PRO-seq_60, K562_PRO-seq_70, K562_PRO-seq_80, K562_PRO-seq_90, K562_PRO-seq_100, K562_RNA-seq_0, K562_RNA-seq_10, K562_RNA-seq_20, K562_RNA-seq_30, K562_RNA-seq_40, K562_RNA-seq_50\n", - "Sections: name, pep_version, sample_table, looper, sample_modifiers\n" - ] - } - ], - "source": [ - "eido inspect peppro_paper.yaml" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " - To inspect a specific sample, one needs to provide the sample name (via `-n`/`--sample-name` oprional argument)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Sample 'K562_RNA-seq_10' in Project (peppro_paper.yaml)\n", - "\n", - "sample_name: K562_RNA-seq_10\n", - "sample_desc: 90% K562 PRO-seq + 10% K562 RNA-seq\n", - "treatment: 70M total reads\n", - "protocol: PRO\n", - "organism: human\n", - "read_type: SINGLE\n", - "umi_len: 0\n", - "read1: /Users/mstolarczyk/K562_10pctRNA.fastq.gz\n", - "srr: K562_10pctRNA\n", - "pipeline_interfaces: $CODE/peppro/sample_pipeline_interface.yaml\n", - "genome: hg38\n", - "\n", - "... (showing first 10)\n", - "\n", - "\n" - ] - } - ], - "source": [ - "eido inspect peppro_paper.yaml -n K562_PRO-seq K562_RNA-seq_10" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## PEP validation" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, let's use `eido` to validate this project against the generic PEP schema. You just need to provide a path to the project config file and schema as an input." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Validation successful\n" - ] - } - ], - "source": [ - "eido validate peppro_paper.yaml -s http://schema.databio.org/pep/2.0.0.yaml -e" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Any PEP should validate against that schema, which describes generic PEP format. We can go one step further and validate it against the PEPPRO schema, which describes Proseq projects specfically for this pipeline:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Validation successful\n" - ] - } - ], - "source": [ - "eido validate peppro_paper.yaml -s http://schema.databio.org/pipelines/ProseqPEP.yaml" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This project would *not* validate against a different pipeline's schema.\n", - "\n", - "Following `jsonschema`, `eido` produces comprehensive error messages that include the objects that did not pass validation. When validating PEPs that include lots of samples one can use option `-e`/`--exclude-case` to limit the error output just to the human readable message. This is the option used in the example below:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Traceback (most recent call last):\n", - " File \"/usr/local/bin/eido\", line 8, in \n", - " sys.exit(main())\n", - " File \"/usr/local/lib/python3.9/site-packages/eido/cli.py\", line 89, in main\n", - " validate_project(p, args.schema, args.exclude_case)\n", - " File \"/usr/local/lib/python3.9/site-packages/eido/validation.py\", line 45, in validate_project\n", - " _validate_object(project_dict, preprocess_schema(schema_dict), exclude_case)\n", - " File \"/usr/local/lib/python3.9/site-packages/eido/validation.py\", line 30, in _validate_object\n", - " raise jsonschema.exceptions.ValidationError(e.message)\n", - "jsonschema.exceptions.ValidationError: 'input_file_path' is a required property\n" - ] - }, - { - "ename": "", - "evalue": "1", - "output_type": "error", - "traceback": [] - } - ], - "source": [ - "eido validate peppro_paper.yaml -s http://schema.databio.org/pipelines/bedmaker.yaml -e" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Optionally, to validate just the config part of the PEP or a specific sample, `-n`/`--sample-name` or `-c`/`--just-config` arguments should be used, respectively. Please refer to the help for more details:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "usage: eido validate [-h] -s S [-e] [-n S | -c] PEP\n", - "\n", - "Validate the PEP or its components.\n", - "\n", - "positional arguments:\n", - " PEP Path to a PEP configuration file in yaml format.\n", - "\n", - "optional arguments:\n", - " -h, --help show this help message and exit\n", - " -s S, --schema S Path to a PEP schema file in yaml format.\n", - " -e, --exclude-case Whether to exclude the validation case from an error.\n", - " Only the human readable message explaining the error\n", - " will be raised. Useful when validating large PEPs.\n", - " -n S, --sample-name S\n", - " Name or index of the sample to validate. Only this\n", - " sample will be validated.\n", - " -c, --just-config Whether samples should be excluded from the\n", - " validation.\n" - ] - } - ], - "source": [ - "eido validate -h" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## PEP conversion\n", - "\n", - "Let's use `eido convert` command to convert PEPs to a variety of different formats. `eido` supports a plugin system, which can be used by other tool developers to create Python plugin functions that save PEPs in a desired format. Please refer to the documentation for more details. For now let's focus on a couple of plugins that are built-in in `eido`.\n", - "\n", - "To see what plugins are currently avaialable in your Python environment call:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Available filters:\n", - " - basic\n", - " - csv\n", - " - yaml\n", - " - yaml-samples\n" - ] - } - ], - "source": [ - "eido filters" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Running plugin basic\n", - "Project 'PEPPRO' (peppro_paper.yaml)\n", - "47 samples (showing first 20): K562_PRO-seq_02, K562_PRO-seq_04, K562_PRO-seq_06, K562_PRO-seq_08, K562_PRO-seq_10, K562_PRO-seq_20, K562_PRO-seq_30, K562_PRO-seq_40, K562_PRO-seq_50, K562_PRO-seq_60, K562_PRO-seq_70, K562_PRO-seq_80, K562_PRO-seq_90, K562_PRO-seq_100, K562_RNA-seq_0, K562_RNA-seq_10, K562_RNA-seq_20, K562_RNA-seq_30, K562_RNA-seq_40, K562_RNA-seq_50\n", - "Sections: name, pep_version, sample_table, looper, sample_modifiers\n" - ] - } - ], - "source": [ - "eido convert peppro_paper.yaml --format basic" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Running plugin csv\n", - "sample_name,genome,organism,pipeline_interfaces,prealignments,protocol,read1,read_type,sample_desc,sample_name,srr,treatment,umi_len,read2\n", - "K562_PRO-seq_02,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_PRO_2pct.fastq.gz,SINGLE,2% subsample of K562 PRO-seq,K562_PRO-seq_02,K562_PRO_2pct,2% subsample,0,\n", - "K562_PRO-seq_04,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_PRO_4pct.fastq.gz,SINGLE,4% subsample of K562 PRO-seq,K562_PRO-seq_04,K562_PRO_4pct,4% subsample,0,\n", - "K562_PRO-seq_06,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_PRO_6pct.fastq.gz,SINGLE,6% subsample of K562 PRO-seq,K562_PRO-seq_06,K562_PRO_6pct,6% subsample,0,\n", - "K562_PRO-seq_08,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_PRO_8pct.fastq.gz,SINGLE,8% subsample of K562 PRO-seq,K562_PRO-seq_08,K562_PRO_8pct,8% subsample,0,\n", - "K562_PRO-seq_10,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_PRO_10pct.fastq.gz,SINGLE,10% subsample of K562 PRO-seq,K562_PRO-seq_10,K562_PRO_10pct,10% subsample,0,\n", - "K562_PRO-seq_20,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_PRO_20pct.fastq.gz,SINGLE,20% subsample of K562 PRO-seq,K562_PRO-seq_20,K562_PRO_20pct,20% subsample,0,\n", - "K562_PRO-seq_30,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_PRO_30pct.fastq.gz,SINGLE,30% subsample of K562 PRO-seq,K562_PRO-seq_30,K562_PRO_30pct,30% subsample,0,\n", - "K562_PRO-seq_40,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_PRO_40pct.fastq.gz,SINGLE,40% subsample of K562 PRO-seq,K562_PRO-seq_40,K562_PRO_40pct,40% subsample,0,\n", - "K562_PRO-seq_50,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_PRO_50pct.fastq.gz,SINGLE,50% subsample of K562 PRO-seq,K562_PRO-seq_50,K562_PRO_50pct,50% subsample,0,\n", - "K562_PRO-seq_60,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_PRO_60pct.fastq.gz,SINGLE,60% subsample of K562 PRO-seq,K562_PRO-seq_60,K562_PRO_60pct,60% subsample,0,\n", - "K562_PRO-seq_70,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_PRO_70pct.fastq.gz,SINGLE,70% subsample of K562 PRO-seq,K562_PRO-seq_70,K562_PRO_70pct,70% subsample,0,\n", - "K562_PRO-seq_80,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_PRO_80pct.fastq.gz,SINGLE,80% subsample of K562 PRO-seq,K562_PRO-seq_80,K562_PRO_80pct,80% subsample,0,\n", - "K562_PRO-seq_90,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_PRO_90pct.fastq.gz,SINGLE,90% subsample of K562 PRO-seq,K562_PRO-seq_90,K562_PRO_90pct,90% subsample,0,\n", - "K562_PRO-seq_100,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/SRR155431[1-2].fastq.gz,SINGLE,Unsampled K562 PRO-seq,K562_PRO-seq_100,SRR155431[1-2],none,0,\n", - "K562_RNA-seq_0,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_0pctRNA.fastq.gz,SINGLE,100% K562 PRO-seq + 0% K562 RNA-seq,K562_RNA-seq_0,K562_0pctRNA,70M total reads,0,\n", - "K562_RNA-seq_10,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_10pctRNA.fastq.gz,SINGLE,90% K562 PRO-seq + 10% K562 RNA-seq,K562_RNA-seq_10,K562_10pctRNA,70M total reads,0,\n", - "K562_RNA-seq_20,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_20pctRNA.fastq.gz,SINGLE,80% K562 PRO-seq + 20% K562 RNA-seq,K562_RNA-seq_20,K562_20pctRNA,70M total reads,0,\n", - "K562_RNA-seq_30,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_30pctRNA.fastq.gz,SINGLE,70% K562 PRO-seq + 30% K562 RNA-seq,K562_RNA-seq_30,K562_30pctRNA,70M total reads,0,\n", - "K562_RNA-seq_40,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_40pctRNA.fastq.gz,SINGLE,60% K562 PRO-seq + 40% K562 RNA-seq,K562_RNA-seq_40,K562_40pctRNA,70M total reads,0,\n", - "K562_RNA-seq_50,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_50pctRNA.fastq.gz,SINGLE,50% K562 PRO-seq + 50% K562 RNA-seq,K562_RNA-seq_50,K562_50pctRNA,70M total reads,0,\n", - "K562_RNA-seq_60,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_60pctRNA.fastq.gz,SINGLE,40% K562 PRO-seq + 60% K562 RNA-seq,K562_RNA-seq_60,K562_60pctRNA,70M total reads,0,\n", - "K562_RNA-seq_70,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_70pctRNA.fastq.gz,SINGLE,30% K562 PRO-seq + 70% K562 RNA-seq,K562_RNA-seq_70,K562_70pctRNA,70M total reads,0,\n", - "K562_RNA-seq_80,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_80pctRNA.fastq.gz,SINGLE,20% K562 PRO-seq + 80% K562 RNA-seq,K562_RNA-seq_80,K562_80pctRNA,70M total reads,0,\n", - "K562_RNA-seq_90,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_90pctRNA.fastq.gz,SINGLE,10% K562 PRO-seq + 90% K562 RNA-seq,K562_RNA-seq_90,K562_90pctRNA,70M total reads,0,\n", - "K562_RNA-seq_100,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/K562_100pctRNA.fastq.gz,SINGLE,0% K562 PRO-seq + 100% K562 RNA-seq,K562_RNA-seq_100,K562_100pctRNA,70M total reads,0,\n", - "K562_GRO-seq,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,GRO,/Users/mstolarczyk/SRR1552484.fastq.gz,SINGLE,K562 GRO-seq,K562_GRO-seq,SRR1552484,none,0,\n", - "HelaS3_GRO-seq,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,GRO,/Users/mstolarczyk/SRR169361[1-2].fastq.gz,SINGLE,HelaS3 GRO-seq,HelaS3_GRO-seq,SRR169361[1-2],none,0,\n", - "Jurkat_ChRO-seq_1,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/SRR7616133.fastq.gz,SINGLE,Jurkat ChRO-seq,Jurkat_ChRO-seq_1,SRR7616133,none,6,\n", - "Jurkat_ChRO-seq_2,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/SRR7616134.fastq.gz,SINGLE,Jurkat ChRO-seq,Jurkat_ChRO-seq_2,SRR7616134,none,6,\n", - "HEK_PRO-seq,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/SRR8608074_PE1.fastq.gz,PAIRED,\"HEK w/ osTIR1, ZNF143AID PRO-seq\",HEK_PRO-seq,SRR8608074,Auxin,8,/Users/mstolarczyk/SRR8608074_PE2.fastq.gz\n", - "HEK_ARF_PRO-seq,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/SRR8608070_PE1.fastq.gz,PAIRED,\"HEK w/ osTIR1, ZNF143AID, ARF PRO-seq\",HEK_ARF_PRO-seq,SRR8608070,Auxin,8,/Users/mstolarczyk/SRR8608070_PE2.fastq.gz\n", - "H9_PRO-seq_1,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/H9_DMSO_rep1_PE1.fastq.gz,PAIRED,H9 PRO-seq,H9_PRO-seq_1,H9_DMSO_rep1,DMSO,8,/Users/mstolarczyk/H9_DMSO_rep1_PE2.fastq.gz\n", - "H9_PRO-seq_2,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/H9_DMSO_rep2_PE1.fastq.gz,PAIRED,H9 PRO-seq,H9_PRO-seq_2,H9_DMSO_rep2,DMSO,8,/Users/mstolarczyk/H9_DMSO_rep2_PE2.fastq.gz\n", - "H9_PRO-seq_3,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/H9_DMSO_rep3_PE1.fastq.gz,PAIRED,H9 PRO-seq,H9_PRO-seq_3,H9_DMSO_rep3,DMSO,8,/Users/mstolarczyk/H9_DMSO_rep3_PE2.fastq.gz\n", - "H9_treated_PRO-seq_1,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/H9_200nM_romidepsin_rep1_PE1.fastq.gz,PAIRED,H9 treated PRO-seq,H9_treated_PRO-seq_1,H9_200nM_romidepsin_rep1,200 nM romidepsin,8,/Users/mstolarczyk/H9_200nM_romidepsin_rep1_PE2.fastq.gz\n", - "H9_treated_PRO-seq_2,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/H9_200nM_romidepsin_rep2_PE1.fastq.gz,PAIRED,H9 treated PRO-seq,H9_treated_PRO-seq_2,H9_200nM_romidepsin_rep2,200 nM romidepsin,8,/Users/mstolarczyk/H9_200nM_romidepsin_rep2_PE2.fastq.gz\n", - "H9_treated_PRO-seq_3,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/H9_200nM_romidepsin_rep3_PE1.fastq.gz,PAIRED,H9 treated PRO-seq,H9_treated_PRO-seq_3,H9_200nM_romidepsin_rep3,200 nM romidepsin,8,/Users/mstolarczyk/H9_200nM_romidepsin_rep3_PE2.fastq.gz\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "H9_PRO-seq_10,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/H9_PRO-seq_10pct_PE1.fastq.gz,PAIRED,10% subset H9 PRO-seq 2,H9_PRO-seq_10,H9_PRO-seq_10pct,DMSO,8,/Users/mstolarczyk/H9_PRO-seq_10pct_PE2.fastq.gz\n", - "H9_PRO-seq_20,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/H9_PRO-seq_20pct_PE1.fastq.gz,PAIRED,20% subset H9 PRO-seq 2,H9_PRO-seq_20,H9_PRO-seq_20pct,DMSO,8,/Users/mstolarczyk/H9_PRO-seq_20pct_PE2.fastq.gz\n", - "H9_PRO-seq_30,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/H9_PRO-seq_30pct_PE1.fastq.gz,PAIRED,30% subset H9 PRO-seq 2,H9_PRO-seq_30,H9_PRO-seq_30pct,DMSO,8,/Users/mstolarczyk/H9_PRO-seq_30pct_PE2.fastq.gz\n", - "H9_PRO-seq_40,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/H9_PRO-seq_40pct_PE1.fastq.gz,PAIRED,40% subset H9 PRO-seq 2,H9_PRO-seq_40,H9_PRO-seq_40pct,DMSO,8,/Users/mstolarczyk/H9_PRO-seq_40pct_PE2.fastq.gz\n", - "H9_PRO-seq_50,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/H9_PRO-seq_50pct_PE1.fastq.gz,PAIRED,50% subset H9 PRO-seq 2,H9_PRO-seq_50,H9_PRO-seq_50pct,DMSO,8,/Users/mstolarczyk/H9_PRO-seq_50pct_PE2.fastq.gz\n", - "H9_PRO-seq_60,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/H9_PRO-seq_60pct_PE1.fastq.gz,PAIRED,60% subset H9 PRO-seq 2,H9_PRO-seq_60,H9_PRO-seq_60pct,DMSO,8,/Users/mstolarczyk/H9_PRO-seq_60pct_PE2.fastq.gz\n", - "H9_PRO-seq_70,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/H9_PRO-seq_70pct_PE1.fastq.gz,PAIRED,70% subset H9 PRO-seq 2,H9_PRO-seq_70,H9_PRO-seq_70pct,DMSO,8,/Users/mstolarczyk/H9_PRO-seq_70pct_PE2.fastq.gz\n", - "H9_PRO-seq_80,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/H9_PRO-seq_80pct_PE1.fastq.gz,PAIRED,80% subset H9 PRO-seq 2,H9_PRO-seq_80,H9_PRO-seq_80pct,DMSO,8,/Users/mstolarczyk/H9_PRO-seq_80pct_PE2.fastq.gz\n", - "H9_PRO-seq_90,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/H9_PRO-seq_90pct_PE1.fastq.gz,PAIRED,90% subset H9 PRO-seq 2,H9_PRO-seq_90,H9_PRO-seq_90pct,DMSO,8,/Users/mstolarczyk/H9_PRO-seq_90pct_PE2.fastq.gz\n", - "H9_PRO-seq_100,hg38,human,['$CODE/peppro/sample_pipeline_interface.yaml'],human_rDNA,PRO,/Users/mstolarczyk/H9_PRO-seq_100pct_PE1.fastq.gz,PAIRED,100% H9 PRO-seq 2,H9_PRO-seq_100,H9_PRO-seq_100pct,DMSO,8,/Users/mstolarczyk/H9_PRO-seq_100pct_PE2.fastq.gz\n" - ] - } - ], - "source": [ - "eido convert peppro_paper.yaml --format csv" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Bash", - "language": "bash", - "name": "bash" - }, - "language_info": { - "codemirror_mode": "shell", - "file_extension": ".sh", - "mimetype": "text/x-sh", - "name": "bash" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/docs_jupyter/demo.ipynb b/docs_jupyter/demo.ipynb deleted file mode 100644 index 6e753779..00000000 --- a/docs_jupyter/demo.ipynb +++ /dev/null @@ -1,375 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Python API usage\n", - "\n", - "There are 3 validation functions in the public `eido` package interface:\n", - "\n", - "- `validate_project` to validate the entire PEP\n", - "- `validate_sample` to validate only a selected sample\n", - "- `validate_config` to validate only the config part of the PEP\n", - "\n", - "Additionally there is a `read_schema` function that lets you read the schema." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Schema reading\n", - "\n", - "As noted above `read_schema` function can be used to read a YAML-formatted schema to Python. Depending on the class of the argument used, it will get a remote schema (argument is a URL) or will read one from disk (argument is a path)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Remote" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'description': 'Schema for a minimal PEP',\n", - " 'version': '2.0.0',\n", - " 'properties': {'config': {'properties': {'name': {'type': 'string',\n", - " 'pattern': '^\\\\S*$',\n", - " 'description': 'Project name with no whitespace'},\n", - " 'pep_version': {'description': 'Version of the PEP Schema this PEP follows',\n", - " 'type': 'string'},\n", - " 'sample_table': {'type': 'string',\n", - " 'description': 'Path to the sample annotation table with one row per sample'},\n", - " 'subsample_table': {'type': 'string',\n", - " 'description': 'Path to the subsample annotation table with one row per subsample and sample_name attribute matching an entry in the sample table'},\n", - " 'sample_modifiers': {'type': 'object',\n", - " 'properties': {'append': {'type': 'object'},\n", - " 'duplicate': {'type': 'object'},\n", - " 'imply': {'type': 'array',\n", - " 'items': {'type': 'object',\n", - " 'properties': {'if': {'type': 'object'},\n", - " 'then': {'type': 'object'}}}},\n", - " 'derive': {'type': 'object',\n", - " 'properties': {'attributes': {'type': 'array',\n", - " 'items': {'type': 'string'}},\n", - " 'sources': {'type': 'object'}}}},\n", - " 'project_modifiers': {'type': 'object',\n", - " 'properties': {'amend': {'description': 'Object overwriting original project attributes',\n", - " 'type': 'object'},\n", - " 'import': {'description': 'List of external PEP project config files to import',\n", - " 'type': 'array',\n", - " 'items': {'type': 'string'}}}}}},\n", - " 'required': ['pep_version']},\n", - " 'samples': {'type': 'array',\n", - " 'items': {'type': 'object',\n", - " 'properties': {'sample_name': {'type': 'string',\n", - " 'pattern': '^\\\\S*$',\n", - " 'description': 'Unique name of the sample with no whitespace'}},\n", - " 'required': ['sample_name']}}},\n", - " 'required': ['samples']}]" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from eido import *\n", - "\n", - "read_schema(\"https://schema.databio.org/pep/2.0.0.yaml\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With this simple call the PEP2.0.0 schema was downloaded from a remote file server and read into a `dict` object in Python." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Local" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'description': 'test PEP schema',\n", - " 'properties': {'dcc': {'type': 'object',\n", - " 'properties': {'compute_packages': {'type': 'object'}}},\n", - " 'samples': {'type': 'array',\n", - " 'items': {'type': 'object',\n", - " 'properties': {'sample_name': {'type': 'string'},\n", - " 'protocol': {'type': 'string'},\n", - " 'genome': {'type': 'string'}}}}},\n", - " 'required': ['samples']}]" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "read_schema(\"../tests/data/schemas/test_schema.yaml\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This time the schema was read from disk." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Schema imports\n", - "\n", - "`eido` lets you import schemas. Schema importing is a very powerful tool to make a cascading system of schemas that will keep the individual building blocks clear and simple.\n", - "\n", - "To import a schema from within a schema one just needs to use an `imports` section somewhere in the schema. The section has to be a YAML list, for example:\n", - "\n", - "```yaml\n", - "imports:\n", - " - ../tests/data/schemas/test_schema.yaml\n", - " - https://schema.databio.org/pep/2.0.0.yaml\n", - "```\n", - "\n", - "or \n", - "\n", - "```yaml\n", - "imports: [../tests/data/schemas/test_schema.yaml, https://schema.databio.org/pep/2.0.0.yaml]\n", - "```\n", - "\n", - "This functionality is particularly useful when one wants to restrict an object that already has a remote schema defined for. For example, to restrict the type of one more sample attribute in a `Project` object (defined by PEP2.0.0 schema).\n", - "\n", - "```yaml\n", - "imports:\n", - " - https://schema.databio.org/pep/2.0.0.yaml\n", - "description: \"Schema for a more restrictive PEP\"\n", - "properties:\n", - " samples:\n", - " type: array\n", - " items:\n", - " type: object\n", - " properties:\n", - " my_numeric_attribute: \n", - " type: integer\n", - " minimum: 0\n", - " maximum: 1\n", - " required:\n", - " - my_numeric_attribute\n", - "required:\n", - " - samples\n", - "```\n", - "\n", - "PEPs to succesfully validate against this schema will need to fulfill all the generic PEP2.0.0 schema requirements _and_ fulfill the new `my_numeric_attribute` requirement.\n", - "\n", - "### How importing works\n", - "\n", - "The output of the `read_schema` function is always a `list` object. In case there are no imports in the read schema it's just a `list` of length 1. \n", - "\n", - "If there are import statements the `list` length reflects the number of schemas imported. Please note that the schemas can be imported recursively, which means that an imported schema can import more schemas. \n", - "\n", - "**The order of the output list is meaningful:**\n", - "\n", - "1. It reflects the order of importing in the \"schema dependency chain\"; the schema used in the `read_schema` call is always last in the output list.\n", - "2. It reflects the order of enumerating schemas in the `imports` section; the order is preserved\n", - "\n", - "This in turn implies the order of the validation in the functions described in detail below." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Entire PEP validation" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "from peppy import Project" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Within Python the `validate_project` function can be used to perform the entire PEP validation. It requires `peppy.Project` object and either a path to the YAML schema file or a read schema (`dict`) as inputs." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "p = Project(\"../tests/data/peps/test_cfg.yaml\")\n", - "validate_project(project=p, schema=\"../tests/data/schemas/test_schema.yaml\")\n", - "\n", - "from eido.eido import load_yaml\n", - "\n", - "s = _load_yaml(\"../tests/data/schemas/test_schema.yaml\")\n", - "validate_project(project=p, schema=s)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If a validation is successful, no message is printed. An unsuccessful one is signalized with a corresponding `jsonschema.exceptions.ValidationError`" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "ename": "ValidationError", - "evalue": "'invalid' is a required property\n\nFailed validating 'required' in schema:\n {'description': 'test PEP schema',\n 'properties': {'_samples': {'items': {'properties': {'genome': {'anyOf': [{'type': 'string'},\n {'items': {'type': 'string'},\n 'type': 'array'}]},\n 'protocol': {'anyOf': [{'type': 'string'},\n {'items': {'type': 'string'},\n 'type': 'array'}]},\n 'sample_name': {'anyOf': [{'type': 'string'},\n {'items': {'type': 'string'},\n 'type': 'array'}]}},\n 'type': 'object'},\n 'type': 'array'},\n 'dcc': {'properties': {'compute_packages': {'type': 'object'}},\n 'type': 'object'},\n 'invalid': {'type': 'string'}},\n 'required': ['_samples', 'invalid']}\n\nOn instance:\n {'_config': {'name': 'test',\n 'output_dir': 'test',\n 'pep_version': '2.0.0',\n 'sample_modifiers': {'append': {'organism': {'Homo sapiens': {'genome': 'hg38'}}}},\n 'sample_table': '/Users/mstolarczyk/code/eido/tests/data/peps/test_sample_table.csv'},\n '_config_file': '/Users/mstolarczyk/code/eido/tests/data/peps/test_cfg.yaml',\n '_sample_df': sample_name protocol genome\n 0 GSM1558746 GRO hg38\n 1 GSM1480327 PRO hg38,\n '_sample_table': genome organism protocol sample_name\n sample_name \n GSM1558746 hg38 {'Homo sapiens': {'genome': 'hg38'}} GRO GSM1558746\n GSM1480327 hg38 {'Homo sapiens': {'genome': 'hg38'}} PRO GSM1480327,\n '_samples': [{'_attributes': ['sample_name', 'protocol', 'genome'],\n '_derived_cols_done': [],\n '_project': {'_config': {'name': 'test',\n 'output_dir': 'test',\n 'pep_version': '2.0.0',\n 'sample_modifiers': {'append': {'organism': {'Homo sapiens': {'genome': 'hg38'}}}},\n 'sample_table': '/Users/mstolarczyk/code/eido/tests/data/peps/test_sample_table.csv'},\n '_config_file': '/Users/mstolarczyk/code/eido/tests/data/peps/test_cfg.yaml',\n '_sample_df': sample_name protocol genome\n 0 GSM1558746 GRO hg38\n 1 GSM1480327 PRO hg38,\n '_sample_table': genome organism protocol sample_name\n sample_name \n GSM1558746 hg38 {'Homo sapiens': {'genome': 'hg38'}} GRO GSM1558746\n GSM1480327 hg38 {'Homo sapiens': {'genome': 'hg38'}} PRO GSM1480327,\n '_samples': ,\n '_samples_touched': True,\n '_subsample_df': None,\n 'description': None,\n 'name': 'test',\n 'sst_index': ['sample_name',\n 'subsample_name'],\n 'st_index': 'sample_name'},\n 'genome': 'hg38',\n 'organism': PathExAttMap\n Homo sapiens:\n genome: hg38,\n 'protocol': 'GRO',\n 'sample_name': 'GSM1558746'},\n {'_attributes': ['sample_name', 'protocol', 'genome'],\n '_derived_cols_done': [],\n '_project': {'_config': {'name': 'test',\n 'output_dir': 'test',\n 'pep_version': '2.0.0',\n 'sample_modifiers': {'append': {'organism': {'Homo sapiens': {'genome': 'hg38'}}}},\n 'sample_table': '/Users/mstolarczyk/code/eido/tests/data/peps/test_sample_table.csv'},\n '_config_file': '/Users/mstolarczyk/code/eido/tests/data/peps/test_cfg.yaml',\n '_sample_df': sample_name protocol genome\n 0 GSM1558746 GRO hg38\n 1 GSM1480327 PRO hg38,\n '_sample_table': genome organism protocol sample_name\n sample_name \n GSM1558746 hg38 {'Homo sapiens': {'genome': 'hg38'}} GRO GSM1558746\n GSM1480327 hg38 {'Homo sapiens': {'genome': 'hg38'}} PRO GSM1480327,\n '_samples': ,\n '_samples_touched': True,\n '_subsample_df': None,\n 'description': None,\n 'name': 'test',\n 'sst_index': ['sample_name',\n 'subsample_name'],\n 'st_index': 'sample_name'},\n 'genome': 'hg38',\n 'organism': PathExAttMap\n Homo sapiens:\n genome: hg38,\n 'protocol': 'PRO',\n 'sample_name': 'GSM1480327'}],\n '_samples_touched': True,\n '_subsample_df': None,\n 'description': None,\n 'name': 'test',\n 'sst_index': ['sample_name', 'subsample_name'],\n 'st_index': 'sample_name'}", - "output_type": "error", - "traceback": [ - "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", - "\u001B[0;31mValidationError\u001B[0m Traceback (most recent call last)", - "\u001B[0;32m\u001B[0m in \u001B[0;36m\u001B[0;34m\u001B[0m\n\u001B[0;32m----> 1\u001B[0;31m \u001B[0mvalidate_project\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0mproject\u001B[0m\u001B[0;34m=\u001B[0m\u001B[0mp\u001B[0m\u001B[0;34m,\u001B[0m \u001B[0mschema\u001B[0m\u001B[0;34m=\u001B[0m\u001B[0;34m\"../tests/data/schemas/test_schema_invalid.yaml\"\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0m", - "\u001B[0;32m/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/eido/eido.py\u001B[0m in \u001B[0;36mvalidate_project\u001B[0;34m(project, schema, exclude_case)\u001B[0m\n\u001B[1;32m 112\u001B[0m \u001B[0;32mfor\u001B[0m \u001B[0mschema_dict\u001B[0m \u001B[0;32min\u001B[0m \u001B[0mschema_dicts\u001B[0m\u001B[0;34m:\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[1;32m 113\u001B[0m \u001B[0mproject_dict\u001B[0m \u001B[0;34m=\u001B[0m \u001B[0mproject\u001B[0m\u001B[0;34m.\u001B[0m\u001B[0mto_dict\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0;32m--> 114\u001B[0;31m \u001B[0m_validate_object\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0mproject_dict\u001B[0m\u001B[0;34m,\u001B[0m \u001B[0m_preprocess_schema\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0mschema_dict\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m,\u001B[0m \u001B[0mexclude_case\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0m\u001B[1;32m 115\u001B[0m \u001B[0m_LOGGER\u001B[0m\u001B[0;34m.\u001B[0m\u001B[0mdebug\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0;34m\"Project validation successful\"\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[1;32m 116\u001B[0m \u001B[0;34m\u001B[0m\u001B[0m\n", - "\u001B[0;32m/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/eido/eido.py\u001B[0m in \u001B[0;36m_validate_object\u001B[0;34m(object, schema, exclude_case)\u001B[0m\n\u001B[1;32m 93\u001B[0m \"\"\"\n\u001B[1;32m 94\u001B[0m \u001B[0;32mtry\u001B[0m\u001B[0;34m:\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0;32m---> 95\u001B[0;31m \u001B[0mjsonschema\u001B[0m\u001B[0;34m.\u001B[0m\u001B[0mvalidate\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0mobject\u001B[0m\u001B[0;34m,\u001B[0m \u001B[0mschema\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0m\u001B[1;32m 96\u001B[0m \u001B[0;32mexcept\u001B[0m \u001B[0mjsonschema\u001B[0m\u001B[0;34m.\u001B[0m\u001B[0mexceptions\u001B[0m\u001B[0;34m.\u001B[0m\u001B[0mValidationError\u001B[0m \u001B[0;32mas\u001B[0m \u001B[0me\u001B[0m\u001B[0;34m:\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[1;32m 97\u001B[0m \u001B[0;32mif\u001B[0m \u001B[0;32mnot\u001B[0m \u001B[0mexclude_case\u001B[0m\u001B[0;34m:\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n", - "\u001B[0;32m/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/jsonschema/validators.py\u001B[0m in \u001B[0;36mvalidate\u001B[0;34m(instance, schema, cls, *args, **kwargs)\u001B[0m\n\u001B[1;32m 932\u001B[0m \u001B[0merror\u001B[0m \u001B[0;34m=\u001B[0m \u001B[0mexceptions\u001B[0m\u001B[0;34m.\u001B[0m\u001B[0mbest_match\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0mvalidator\u001B[0m\u001B[0;34m.\u001B[0m\u001B[0miter_errors\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0minstance\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[1;32m 933\u001B[0m \u001B[0;32mif\u001B[0m \u001B[0merror\u001B[0m \u001B[0;32mis\u001B[0m \u001B[0;32mnot\u001B[0m \u001B[0;32mNone\u001B[0m\u001B[0;34m:\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0;32m--> 934\u001B[0;31m \u001B[0;32mraise\u001B[0m \u001B[0merror\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0m\u001B[1;32m 935\u001B[0m \u001B[0;34m\u001B[0m\u001B[0m\n\u001B[1;32m 936\u001B[0m \u001B[0;34m\u001B[0m\u001B[0m\n", - "\u001B[0;31mValidationError\u001B[0m: 'invalid' is a required property\n\nFailed validating 'required' in schema:\n {'description': 'test PEP schema',\n 'properties': {'_samples': {'items': {'properties': {'genome': {'anyOf': [{'type': 'string'},\n {'items': {'type': 'string'},\n 'type': 'array'}]},\n 'protocol': {'anyOf': [{'type': 'string'},\n {'items': {'type': 'string'},\n 'type': 'array'}]},\n 'sample_name': {'anyOf': [{'type': 'string'},\n {'items': {'type': 'string'},\n 'type': 'array'}]}},\n 'type': 'object'},\n 'type': 'array'},\n 'dcc': {'properties': {'compute_packages': {'type': 'object'}},\n 'type': 'object'},\n 'invalid': {'type': 'string'}},\n 'required': ['_samples', 'invalid']}\n\nOn instance:\n {'_config': {'name': 'test',\n 'output_dir': 'test',\n 'pep_version': '2.0.0',\n 'sample_modifiers': {'append': {'organism': {'Homo sapiens': {'genome': 'hg38'}}}},\n 'sample_table': '/Users/mstolarczyk/code/eido/tests/data/peps/test_sample_table.csv'},\n '_config_file': '/Users/mstolarczyk/code/eido/tests/data/peps/test_cfg.yaml',\n '_sample_df': sample_name protocol genome\n 0 GSM1558746 GRO hg38\n 1 GSM1480327 PRO hg38,\n '_sample_table': genome organism protocol sample_name\n sample_name \n GSM1558746 hg38 {'Homo sapiens': {'genome': 'hg38'}} GRO GSM1558746\n GSM1480327 hg38 {'Homo sapiens': {'genome': 'hg38'}} PRO GSM1480327,\n '_samples': [{'_attributes': ['sample_name', 'protocol', 'genome'],\n '_derived_cols_done': [],\n '_project': {'_config': {'name': 'test',\n 'output_dir': 'test',\n 'pep_version': '2.0.0',\n 'sample_modifiers': {'append': {'organism': {'Homo sapiens': {'genome': 'hg38'}}}},\n 'sample_table': '/Users/mstolarczyk/code/eido/tests/data/peps/test_sample_table.csv'},\n '_config_file': '/Users/mstolarczyk/code/eido/tests/data/peps/test_cfg.yaml',\n '_sample_df': sample_name protocol genome\n 0 GSM1558746 GRO hg38\n 1 GSM1480327 PRO hg38,\n '_sample_table': genome organism protocol sample_name\n sample_name \n GSM1558746 hg38 {'Homo sapiens': {'genome': 'hg38'}} GRO GSM1558746\n GSM1480327 hg38 {'Homo sapiens': {'genome': 'hg38'}} PRO GSM1480327,\n '_samples': ,\n '_samples_touched': True,\n '_subsample_df': None,\n 'description': None,\n 'name': 'test',\n 'sst_index': ['sample_name',\n 'subsample_name'],\n 'st_index': 'sample_name'},\n 'genome': 'hg38',\n 'organism': PathExAttMap\n Homo sapiens:\n genome: hg38,\n 'protocol': 'GRO',\n 'sample_name': 'GSM1558746'},\n {'_attributes': ['sample_name', 'protocol', 'genome'],\n '_derived_cols_done': [],\n '_project': {'_config': {'name': 'test',\n 'output_dir': 'test',\n 'pep_version': '2.0.0',\n 'sample_modifiers': {'append': {'organism': {'Homo sapiens': {'genome': 'hg38'}}}},\n 'sample_table': '/Users/mstolarczyk/code/eido/tests/data/peps/test_sample_table.csv'},\n '_config_file': '/Users/mstolarczyk/code/eido/tests/data/peps/test_cfg.yaml',\n '_sample_df': sample_name protocol genome\n 0 GSM1558746 GRO hg38\n 1 GSM1480327 PRO hg38,\n '_sample_table': genome organism protocol sample_name\n sample_name \n GSM1558746 hg38 {'Homo sapiens': {'genome': 'hg38'}} GRO GSM1558746\n GSM1480327 hg38 {'Homo sapiens': {'genome': 'hg38'}} PRO GSM1480327,\n '_samples': ,\n '_samples_touched': True,\n '_subsample_df': None,\n 'description': None,\n 'name': 'test',\n 'sst_index': ['sample_name',\n 'subsample_name'],\n 'st_index': 'sample_name'},\n 'genome': 'hg38',\n 'organism': PathExAttMap\n Homo sapiens:\n genome: hg38,\n 'protocol': 'PRO',\n 'sample_name': 'GSM1480327'}],\n '_samples_touched': True,\n '_subsample_df': None,\n 'description': None,\n 'name': 'test',\n 'sst_index': ['sample_name', 'subsample_name'],\n 'st_index': 'sample_name'}" - ] - } - ], - "source": [ - "validate_project(project=p, schema=\"../tests/data/schemas/test_schema_invalid.yaml\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Config validation" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Similarily, the config part of the PEP can be validated; the function inputs remain the same" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "validate_config(project=p, schema=\"../tests/data/schemas/test_schema.yaml\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Sample validation" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To validate a specific `peppy.Sample` object within a PEP, one needs to also specify the `sample_name` argument which can be the `peppy.Sample.name` attribute (`str`) or the ID of the sample (`int`)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "validate_sample(\n", - " project=p, schema=\"../tests/data/schemas/test_schema.yaml\", sample_name=0\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Output details\n", - "\n", - "As depicted above the error raised by the `jsonschema` package is very detailed. That's because the entire validated PEP is printed out for the user reference. Since it can get overwhelming in case of the multi sample PEPs each of the `eido` functions presented above privide a way to limit the output to just the general information indicating the unmet schema requirements" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "ename": "ValidationError", - "evalue": "'invalid' is a required property", - "output_type": "error", - "traceback": [ - "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", - "\u001B[0;31mValidationError\u001B[0m Traceback (most recent call last)", - "\u001B[0;32m\u001B[0m in \u001B[0;36m\u001B[0;34m\u001B[0m\n\u001B[1;32m 2\u001B[0m \u001B[0mproject\u001B[0m\u001B[0;34m=\u001B[0m\u001B[0mp\u001B[0m\u001B[0;34m,\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[1;32m 3\u001B[0m \u001B[0mschema\u001B[0m\u001B[0;34m=\u001B[0m\u001B[0;34m\"../tests/data/schemas/test_schema_invalid.yaml\"\u001B[0m\u001B[0;34m,\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0;32m----> 4\u001B[0;31m \u001B[0mexclude_case\u001B[0m\u001B[0;34m=\u001B[0m\u001B[0;32mTrue\u001B[0m\u001B[0;34m,\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0m\u001B[1;32m 5\u001B[0m )\n", - "\u001B[0;32m/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/eido/eido.py\u001B[0m in \u001B[0;36mvalidate_project\u001B[0;34m(project, schema, exclude_case)\u001B[0m\n\u001B[1;32m 112\u001B[0m \u001B[0;32mfor\u001B[0m \u001B[0mschema_dict\u001B[0m \u001B[0;32min\u001B[0m \u001B[0mschema_dicts\u001B[0m\u001B[0;34m:\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[1;32m 113\u001B[0m \u001B[0mproject_dict\u001B[0m \u001B[0;34m=\u001B[0m \u001B[0mproject\u001B[0m\u001B[0;34m.\u001B[0m\u001B[0mto_dict\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0;32m--> 114\u001B[0;31m \u001B[0m_validate_object\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0mproject_dict\u001B[0m\u001B[0;34m,\u001B[0m \u001B[0m_preprocess_schema\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0mschema_dict\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m,\u001B[0m \u001B[0mexclude_case\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0m\u001B[1;32m 115\u001B[0m \u001B[0m_LOGGER\u001B[0m\u001B[0;34m.\u001B[0m\u001B[0mdebug\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0;34m\"Project validation successful\"\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[1;32m 116\u001B[0m \u001B[0;34m\u001B[0m\u001B[0m\n", - "\u001B[0;32m/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/eido/eido.py\u001B[0m in \u001B[0;36m_validate_object\u001B[0;34m(object, schema, exclude_case)\u001B[0m\n\u001B[1;32m 97\u001B[0m \u001B[0;32mif\u001B[0m \u001B[0;32mnot\u001B[0m \u001B[0mexclude_case\u001B[0m\u001B[0;34m:\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[1;32m 98\u001B[0m \u001B[0;32mraise\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0;32m---> 99\u001B[0;31m \u001B[0;32mraise\u001B[0m \u001B[0mjsonschema\u001B[0m\u001B[0;34m.\u001B[0m\u001B[0mexceptions\u001B[0m\u001B[0;34m.\u001B[0m\u001B[0mValidationError\u001B[0m\u001B[0;34m(\u001B[0m\u001B[0me\u001B[0m\u001B[0;34m.\u001B[0m\u001B[0mmessage\u001B[0m\u001B[0;34m)\u001B[0m\u001B[0;34m\u001B[0m\u001B[0m\n\u001B[0m\u001B[1;32m 100\u001B[0m \u001B[0;34m\u001B[0m\u001B[0m\n\u001B[1;32m 101\u001B[0m \u001B[0;34m\u001B[0m\u001B[0m\n", - "\u001B[0;31mValidationError\u001B[0m: 'invalid' is a required property" - ] - } - ], - "source": [ - "validate_project(\n", - " project=p,\n", - " schema=\"../tests/data/schemas/test_schema_invalid.yaml\",\n", - " exclude_case=True,\n", - ")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.5" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/mkdocs.yml b/mkdocs.yml deleted file mode 100644 index dcb5eee8..00000000 --- a/mkdocs.yml +++ /dev/null @@ -1,33 +0,0 @@ -site_name: eido -site_logo: img/eido_dark.svg -site_url: http://eido.databio.org/ -repo_url: http://github.com/pepkit/eido -pypi_name: eido -paper_link: https://doi.org/10.1101/2020.10.08.331322 - -nav: - - Getting Started: - - Introduction: README.md - - Install and configure: install.md - - How-to Guides: - - "Tutorial: eido in Python": demo.md - - "Tutorial: eido in a shell": cli.md - - Using eido filters: filters.md - - Writing a custom filter: writing-a-filter.md - - Writing a schema: writing-a-schema.md - - Reference: - - Example schemas: example-schemas.md - - Eido Python API: autodoc_build/eido.md - - Built-in filters API: plugin_api_docs.md - - Support: https://github.com/pepkit/eido/issues - - Contributing: contributing.md - - Changelog: changelog.md - -theme: databio - -plugins: - - databio: - autodoc_build: "docs/autodoc_build" - autodoc_package: "eido" - no_top_level: true - - search diff --git a/update_api_docs.sh b/update_api_docs.sh deleted file mode 100755 index e92d9366..00000000 --- a/update_api_docs.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -lucidoc eido -P rst --blacklist basic_pep_filter,yaml_pep_filter,csv_pep_filter,yaml_samples_pep_filter > docs/api_docs.md diff --git a/update_plugins_api_docs.sh b/update_plugins_api_docs.sh deleted file mode 100755 index 36bf1bd9..00000000 --- a/update_plugins_api_docs.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -lucidoc eido -P rst --whitelist basic_pep_filter,yaml_pep_filter,csv_pep_filter,yaml_samples_pep_filter > docs/plugin_api_docs.md