diff --git a/.gitignore b/.gitignore index b7ea353..000f680 100755 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,11 @@ +/bin /docs/API.md .idea *.iml +/VERSION.txt node_modules -!/bin /.project /.settings/* npm-debug.log coverage +nohup.out diff --git a/LICENSE.md b/LICENSE.md index c0c4498..cd94487 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2016 Jens Krefeldt +Copyright (c) 2016 [Jens Krefeldt](https://github.com/deadratfink) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index b09b8e6..49443b9 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,35 @@ +![jy-transform logo](https://github.com/deadratfink/jy-transform/blob/master/image/jytransform.png) + # Stats -| [Github License](https://github.com/deadratfink/jy-transform/blob/master/LICENSE.md) | [Github Issues](https://github.com/deadratfink/jy-transform/issues) | [Github Release](https://github.com/deadratfink/jy-transform/releases) | [Github Tags](https://github.com/deadratfink/jy-transform/tags) | [Travis CI](https://travis-ci.org) | [Waffle](https://waffle.io/deadratfink/jy-transform) | [Code Climate](https://codeclimate.com/github/deadratfink/jy-transform) | +## General + +| [License](https://github.com/deadratfink/jy-transform/blob/master/LICENSE.md) | [Issues](https://github.com/deadratfink/jy-transform/issues) | [Releases](https://github.com/deadratfink/jy-transform/releases) | [Tags](https://github.com/deadratfink/jy-transform/tags) | [Travis CI](https://travis-ci.org) | [Waffle](https://waffle.io/deadratfink/jy-transform) | [Code Climate](https://codeclimate.com/github/deadratfink/jy-transform) | | --- | --- | --- | --- | --- | --- | --- | -| [![License][gh-license-image]][gh-license-url] | [![Issue Stats][gh-issues-image]][gh-issues-url] | [![Github Releases][gh-releases-image]][gh-releases-url] | [![Github Tags][gh-tags-image]][gh-tags-url] | [![Build Status][ci-image]][ci-url] | [![Waffle][waffle-image]][waffle-url] | [![Code Climate][cocl-image]][cocl-url] | +| [![License][gh-license-image]][gh-license-url] | [![Issue Stats][gh-issues-image]][gh-issues-url] | [![Releases][gh-releases-image]][gh-releases-url] | [![Tags][gh-tags-image]][gh-tags-url] | [![Build Status][ci-image]][ci-url] | [![Waffle][waffle-image]][waffle-url] | [![Code Climate][cocl-image]][cocl-url] | + +## Branches | Branch | [Codecov](https://codecov.io) | [Coveralls](https://coveralls.io) | [Inch CI](http://inch-ci.org) | [David](https://david-dm.org) DM | [David](https://david-dm.org) DM (dev) | | --- | --- | --- | --- | --- | --- | | master | [![codecov.io][cc-image-master]][cc-url-master] | [![coveralls.io][ca-image-master]][ca-url-master] | [![inch-ci.org][inch-image-master]][inch-url-master] | [![Dependency Status][dep-image-master]][dep-url-master] | [![devDependency Status][devdep-image-master]][devdep-url-master] | | development | [![codecov.io][cc-image-development]][cc-url-development] | [![coveralls.io][ca-image-development]][ca-url-development] | [![inch-ci.org][inch-image-development]][inch-url-development] | [![Dependency Status][dep-image-development]][dep-url-development] | [![devDependency Status][devdep-image-development]][devdep-url-development] | -## Coverage Graphs +### Coverage -| Branch | Graph | +| master | development | | --- | --- | -| master | ![codecov.io](https://codecov.io/github/deadratfink/jy-transform/branch.svg?branch=master&vg=true) | -| development| ![codecov.io](https://codecov.io/github/deadratfink/jy-transform/branch.svg?branch=development&vg=true) | +| ![codecov.io](https://codecov.io/gh/deadratfink/jy-transform/branch/master/graphs/tree.svg) | ![codecov.io](https://codecov.io/gh/deadratfink/jy-transform/branch/development/graphs/tree.svg) | + + + + + + +## NPM +[![NPM](https://nodei.co/npm/jy-transform.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/jy-transform/) +[![NPM](https://nodei.co/npm-dl/jy-transform.png?height=3&months=9)](https://nodei.co/npm-dl/jy-transform/) [gh-license-image]: https://img.shields.io/github/license/deadratfink/jy-transform.svg?style=flat-square [gh-license-url]: https://github.com/deadratfink/jy-transform/blob/master/LICENSE.md @@ -90,14 +104,14 @@ - [API Usage](#api-usage) - [Using Custom Logger](#using-custom-logger) - [API Reference](#api-reference) -- [Changelog](#changelog) - [Contributing](#contributing) +- [Changelog](#changelog) # jy-transform -This project aims to read, write and transform YAML, JS or JSON objects into each other using CLI or API. The source and destination resources can be files on CLI and additionally, objects or streams on API level. Besides the transformation feature this module can also be used for simple loading and/or writing YAML, JS or JSON files. +This project aims to read, write and transform YAML, JS or JSON objects into each other using CLI or API, while the source and destination resources can be files on CLI and additionally, objects or streams on API level. ## Installation @@ -118,7 +132,7 @@ npm test ## Dependencies - [bluebird](https://github.com/petkaantonov/bluebird): Full featured Promises/A+ implementation with exceptionally good performance -- [cli](https://github.com/chriso/cli): A tool for rapidly building command line apps +- [cli](https://github.com/node-js-libs/cli): A tool for rapidly building command line apps - [is-stream](https://github.com/sindresorhus/is-stream): Check if something is a Node.js stream - [js-yaml](https://github.com/nodeca/js-yaml): YAML 1.2 parser and serializer - [json-stringify-safe](https://github.com/isaacs/json-stringify-safe): Like JSON.stringify, but doesn't blow up on circular refs. @@ -137,7 +151,7 @@ npm test - [jsdoc-to-markdown](https://github.com/jsdoc2md/jsdoc-to-markdown): jsdoc-annotated source in, markdown API docs out. - [mocha](https://github.com/mochajs/mocha): simple, flexible, fun test framework - [mocha-lcov-reporter](https://github.com/StevenLooman/mocha-lcov-reporter): LCOV reporter for Mocha -- [object-path](https://github.com/mariocasciaro/object-path): Access deep properties using a path +- [object-path](https://github.com/mariocasciaro/object-path): Access deep object properties using a path - [package-json-to-readme](https://github.com/zeke/package-json-to-readme): Generate a README.md from package.json contents - [winston](https://github.com/winstonjs/winston): A multi-transport async logging library for Node.js @@ -148,15 +162,15 @@ SEE LICENSE IN [LICENSE.md](https://github.com/deadratfink/jy-transform/blob/mas ## Motivation -Why this module? After struggling with some huge YAML file and accidentally -occurring wrong indentions which results in an annoying failure investigation, -I decided to get rid of the YAML file and therefore, create a module which -should be aimed as the swiss army knife for transforming YAML, JS and JSON +Why this module? After struggling with some huge YAML file and accidentally +occurring wrong indentions which results in an annoying failure investigation, +I decided to get rid of the YAML file and therefore, create a module which +should be aimed as the swiss army knife for transforming YAML, JS and JSON types into each other format. # Usage -The module can be used on CLI or as API (the latter is fully [Promise](http://bluebirdjs.com/docs/api-reference.html) +The module can be used on CLI or as API (the latter is fully [Promise](http://bluebirdjs.com/docs/api-reference.html) based). ## Usage Types @@ -186,34 +200,37 @@ Reading from: - _*.js_ file - _*.json_ file -Additionally, on API level: +Additionally, on API level to a: -- `stream.Readable` (requires `options.origin` property set, reads as UTF-8) -- any JS `object` (actually, this means the reading phase is skipped, because object is in-memory already) +- `stream.Readable` + - Serialized JSON and YAML + - Requires `options.origin` property set + - Reads as UTF-8 +- JS `object` (actually, this means the reading phase is skipped, because object is in-memory already) ### Transformation The transformation can take place into several directions: -- YAML => JS -- YAML => JSON -- JS => YAML -- JSON => YAML -- JS => JSON -- JSON => JS -- YAML => YAML -- JSON => JSON -- JS => JS +- YAML ⇒ JS +- YAML ⇒ JSON +- JS ⇒ YAML +- JSON ⇒ YAML +- JS ⇒ JSON +- JSON ⇒ JS +- YAML ⇒ YAML +- JSON ⇒ JSON +- JS ⇒ JS while: - [YAML](http://http://yaml.org/) = _*.yaml_, _*.yml_ -- [JS](https://developer.mozilla.org/en-US/docs/Web/JavaScript) = _*.js_ (JS object) +- [JS](https://developer.mozilla.org/en-US/docs/Web/JavaScript) = _*.js_ (JS object) - [JSON](http://json.org) = _*.json_ (JS object serialized as JSON) ### Middleware -Apply actions on the intermediate JS object via injected [Promise](http://bluebirdjs.com/docs/api-reference.html) +Apply actions on the intermediate JS object via injected [Promise](http://bluebirdjs.com/docs/api-reference.html) functions. This is an optional part for [transformation](#transformation) phase. ### Writing @@ -224,14 +241,17 @@ Writing to: - _*.js_ file - _*.json_ file -Additionally, on API level: +Additionally, on API level to a: -- `stream.Writable` (requires `options.target` property set, writes UTF-8) -- any JS `object` +- `stream.Writable` + - Serialized JS, JSON and YAML + - Requires `options.target` property set + - Writes UTF-8 +- JS `object` ## Limitations -- Since this module is build to transform from and to different type formats, any +- Since this module is build to transform from and to different type formats, any `Function`s residing in JS type objects are _not_ supported, e.g. transforming ```javascript module.exports = { @@ -239,83 +259,75 @@ Additionally, on API level: fooFunction: foo() {...} } ``` - to JSON would simply result in + to JSON would simply result in ```javascript { fooKey: 'foo' } ``` - while transforming to YAML type would even result in an `Error`, e.g. printed + while transforming to YAML type would even result in an `Error`, e.g. printed on CLI usage like this: ``` ERROR: YAMLException: unacceptable kind of an object to dump [object Function] ``` -- Multidocument handling would be a cool feature which refers in general to YAML - and JS only, but at the moment we require that each document to transform is a - _single_ one per source (or in case of JS could be identified)! This feature is +- Multidocument handling would be a cool feature which refers in general to YAML + and JS only, but at the moment we require that each document to transform is a + _single_ one per source (or in case of JS could be identified)! This feature is planned and reflected in [#14](https://github.com/deadratfink/jy-transform/issues/14). -- Schema validation for input and output is another topic which is planned by - [#1](https://github.com/deadratfink/jy-transform/issues/1) and +- Schema validation for input and output is another topic which is planned by + [#1](https://github.com/deadratfink/jy-transform/issues/1) and [#2](https://github.com/deadratfink/jy-transform/issues/2). ## CLI Usage -The CLI provides the `jyt` command (actually, this requires the use of options). -After the global installation you can access the `Transformer` command options -with the usual help command as follows: - -``` -$ jyt --help -``` - -### CLI Options - -The `--help` option prints an overview about all available CLI properties: +The CLI provides the `jyt` command (actually, this requires the use of options). +After the global installation you can access the `Transformer` command options +with the usual command option `--help` option which prints an overview about all +available CLI properties: ``` $ jyt --help Usage: - jyt [OPTIONS] - -Options: - -o, --origin [STRING] The conversion origin: [ js | json | yaml ]. (Default is : if not given, the type is tried to be inferred from the extension of source path, else it is yaml) - -t, --target [STRING] The conversion target: [ js | json | yaml ]. (Default is : if not given, the type is tried to be inferred from the extension of destination path, else it is js) - -s, --src PATH The absolute/relative input file path. - -d, --dest [PATH] The absolute/relative output file path. When this - options is ommited then the output file is stored - relative to the input file (same base name but with - another extension if type differs). If input and - output type are the same then the file overwriting is - handled depending on the '--force' value! (Default is storing relative to input file) - -i, --indent [NUMBER] The indention for pretty-print: 1 - 8. (Default is 4) - -f, --force Force overwriting of existing output files on write - phase. When files are not overwritten (which is - default), then the next transformation with same - output file name gets a consecutive number on the base - file name, e.g. in case of foo.yaml it would be - foo(1).yaml. - -m, --imports STRING Define a 'module.exports[.identifier] = ' - identifier (to read from JS _source_ file only, must - be a valid JS identifier!). - -x, --exports STRING Define a 'module.exports[.identifier] = ' - identifier, for usage in JS destination file only, - must be a valid JS identifier! + jyt INPUT-FILE [OUTPUT-FILE] [OPTIONS] + +Options: + -o, --origin [STRING] The origin type of INPUT-FILE: [ js | json | yaml ]. (Default is if not given, the type is tried to be inferred from the extension of source path, else it is 'yaml') + -t, --target [STRING] The target type of OUTPUT-FILE: [ js | json | yaml ]. (Default is if not given, the type is tried to be inferred from the extension of destination path, else it is 'js') + -i, --indent [NUMBER] The indention for pretty-print: 1 - 8. (Default is 4) + -f, --force Force overwriting of existing output files on write phase. When files are not overwritten (which is default), + then the next transformation with same output file name gets a consecutive number on the base file name, e.g. in + case of foo.yaml it would be foo(1).yaml. + -m, --imports STRING Define a 'module.exports[.identifier] = ' identifier (to read from JS _source_ file only, must be a valid JS + identifier!). + -x, --exports STRING Define a 'module.exports[.identifier] = ' identifier (for usage in JS destination file only, must be a valid JS + identifier!). -k, --no-color Omit color from output --debug Show debug information -v, --version Display the current version -h, --help Display help and usage details ``` -These are more formally defined in the following table: +### CLI Args + +The ARGS are more formally defined in the following table: + +| Arg | Type | Description | Default | Required | +| --- | --- | --- | --- | --- | +| `INPUT-FILE` | URI | The source file path for transformation. | - | yes | +| `OUTPUT-FILE` | URI | The destination file path to transform to. | When this options is omitted then the output file is stored relative to the input file (same base name but with another extension if type differs). If input and output type are the same then the file overwriting is handled depending on the `--force` value! | no | + +**NOTE:** the input file has to be specified and should _first_ argument (in fact, it can be anywhere but it must be before an out file argument)! + +### CLI Options + +The OPTIONS are more formally defined in the following table: | Option (short) | Option (long) | Type | Description | Default | Required | | --- | --- | --- | --- | --- | --- | -| `-o` | `--origin` | [ _js_ | _json_ | _yaml_ ] | The transformation origin type. | if not given, the type is tried to be inferred from the extension of source path, else it is _yaml_ | no | -| `-t` | `--target` | [ _js_ | _json_ | _yaml_ ] | The transformation target type. | if not given, the type is tried to be inferred from the extension of destination path, else it is _js_ | no | -| `-s` | `--src` | URI | The source file path for transformation. | - | yes | -| `-d` | `--dest` | URI | The destination file path to transform to. | When this options is ommited then the output file is stored relative to the input file (same base name but with another extension if type differs). If input and output type are the same then the file overwriting is handled depending on the `--force` value! | no | -| `-i` | `--indent` | integer
- [ 1 - 8 ]
| The code indention used in destination files. | 4 | no | -| `-f` | `--force` | n/a | Force overwriting of existing output files on write phase. When files are not overwritten (which is default), then the next transformation with same output file name gets a consecutive number on the base file name, e.g. in case of foo.yaml it would be foo(1).yaml. | _false_ | no | +| `-o` | `--origin` | string of: [ _js_ | _json_ | _yaml_ ] | The transformation origin type. | if not given, the type is tried to be inferred from the extension of source path, else it is _yaml_ | no | +| `-t` | `--target` | string of: [ _js_ | _json_ | _yaml_ ] | The transformation target type. | if not given, the type is tried to be inferred from the extension of destination path, else it is _js_ | no | +| `-i` | `--indent` | integer
[ 1 - 8 ]
| The code indention used in destination files. | 4 | no | +| `-f` | `--force` | n/a | Force overwriting of existing output files on write phase. When files are not overwritten (which is default), then the next transformation with same output file name gets a consecutive number on the base file name, e.g. in case of _foo.yaml_ it would be _foo(1).yaml_. | _false_ | no | | `-m` | `--imports` | string | Define a 'module.exports[.identifier] = ' identifier (to read from JS _source_ file only, must be a valid JS identifier!) | _undefined_ | no | | `-x` | `--exports` | string | Define a 'module.exports[.identifier] = ' identifier (for usage in JS _destination_ file only, must be a valid JS identifier!) | _undefined_ | no | | `-k` | `--no-color` | n/a | Omit color from output. | _color_ | no | @@ -324,18 +336,17 @@ These are more formally defined in the following table: | `-h` | `--help` | n/a | Display help and usage details. | n/a | no | - **NOTE:** an invalid indention setting (1 > `-i`, `--indent` > 8) does not raise an error but a default of 4 SPACEs is applied instead. ### Examples -Now we know which properties we can apply on CLI, so let's assume we +Now we know which properties we can apply on CLI, so let's assume we have a YAML file located in _foo.yaml_ holding this data: ```yaml foo: bar ``` -#### Example: YAML => JSON +#### Example: YAML ⇒ JSON then we can transform it to a JSON file _foo.json_ @@ -348,29 +359,29 @@ then we can transform it to a JSON file _foo.json_ using this command: ``` -$ jyt -s foo.yaml -t json -i 2 +$ jyt foo.yaml -t json -i 2 ``` -In this example we have overwritten the standard target type (which is `js`) -and applying an indent of _2_ instead of the default _4_. As default the output -file _foo.json_ is written relative to the input file (simply omitting the +In this example we have overwritten the standard target type (which is `js`) +and applying an indent of 2 instead of the default 4. As default the output +file _foo.json_ is written relative to the input file (simply omitting the `dest` option here). -**NOTE:** here you _have_ to provide the target with `-t json` or else the -default `js` would have been applied! If the source would have been a `js` +**NOTE:** here you _have_ to provide the target with `-t json` or else the +default `js` would have been applied! If the source would have been a `js` type like ``` -$ jyt -s foo.js -t json -i 2 +$ jyt foo.js -t json -i 2 ``` -then the `js` value for `origin` is automatically inferred from file extension. +then the `js` value for `origin` is automatically inferred from file extension. Accordingly, this is also true for the `target` option. -#### Example: JSON => JS +#### Example: JSON ⇒ JS ``` -$ jyt -s foo.json -i 2 +$ jyt foo.json -i 2 ``` ```javascript module.exports = { @@ -378,10 +389,10 @@ module.exports = { } ``` -#### Example: JS => YAML +#### Example: JS ⇒ YAML ``` -$ jyt -s foo.js -t yaml +$ jyt foo.js -t yaml ``` ```yaml foo: bar @@ -389,27 +400,27 @@ foo: bar #### Example: Transformation with Different Destination -Simply provide the `-d` with a different file name: +Simply specify the _output_ file with a different file name: ``` -$ jyt -s foo.json -d results/foobar.yaml +$ jyt foo.json results/foobar.yaml ``` #### Example: Transformation with Unsupported Source File Extension -As said, normally we infer from file extension to the type but assume the source -file has a file name which does not imply the type (here JS -type in a TEXT file), then you can simply provide the `-o` option with the +As said, normally we infer from file extension to the type but assume the source +file has a file name which does not imply the type (here a JSON +type in a TEXT file), then you can simply provide the `-o` option with the correct `origin` type (of course, the `-t` option works analogous): ``` -$ jyt -s foo.txt -o js -d foobar.yaml +$ jyt foo.txt foobar.yaml -o json ``` #### Example: Read from File with Exports Identifier -It could be that a JS source `exports` several objects and you want to read +It could be that a JS source `exports` several objects and you want to read from exactly the one you specify, then provide the `-m` (`--imports`) option. In this this example we have a _foo.js_ file exporting _two_ objects: @@ -427,7 +438,7 @@ module.exports.bar = { but you want to convert `bar` object, then call: ``` -$ jyt -s foo.js -m bar -d bar.yaml +$ jyt foo.js bar.yaml -m bar ``` to get the YAML result: @@ -465,8 +476,8 @@ as sub-node of `options.dest`. #### Example: Write Exports Identifier for JS File -Assume you want to generate a JS file with an exports string which gets an -identifier. We reuse the YAML file from above +Assume you want to generate a JS file with an exports string which gets an +identifier. We reuse the YAML file from above ```yaml foo: bar @@ -475,7 +486,7 @@ foo: bar using this command: ``` -$ jyt -s foo.yaml -d foobar.js -x foobar +$ jyt foo.yaml foobar.js -x foobar ``` This generates the following output in JS file using `foobar` as identifier: @@ -487,33 +498,33 @@ module.exports.foobar = { ``` **NOTE:** the identifier must be a valid JS identifier accoding to ECMAScript 6 -(see also [Valid JavaScript variable names in ECMAScript 6](https://mathiasbynens.be/notes/javascript-identifiers-es6) +(see also [Valid JavaScript variable names in ECMAScript 6](https://mathiasbynens.be/notes/javascript-identifiers-es6) and [Generating a regular expression to match valid JavaScript identifiers](https://mathiasbynens.be/demo/javascript-identifier-regex)). #### Example: Force Overwriting -**IMPORTANT NOTE:** when using this feature then any subsequent -execution which uses the same target/file name, +**IMPORTANT NOTE:** when using this feature then any subsequent +execution which uses the same target/file name, will overwrite the original source or target created beforehand! -By default this feature is not enabled to prevent you from accidentally +By default this feature is not enabled to prevent you from accidentally overwriting your input source or already generated targets. -But let's say we want to overwrite the original source now because you want +But let's say we want to overwrite the original source now because you want to change the indention from 2 to 4 SPACEs, then we can do this as follows: ``` -$ jyt -s foo.js -f -``` +$ jyt foo.js -f +``` -Of course, leaving out the `-f` switch creates a new file relatively to -the `origin`, named as _foo(1).js_ (note the consecutive number). Naturally, -another run of the command would result int a file called _foo(2).js_ +Of course, leaving out the `-f` switch creates a new file relatively to +the `origin`, named as _foo(1).js_ (note the consecutive number). Naturally, +another run of the command would result in a file called _foo(2).js_ and so forth. ## Origin and Target Type Inference -The examples above have shown that we have an automatic type inference from file +The examples above have shown that we have an automatic type inference from file extensions. This is supported as shown by the following table (from-to): | File Extension | Type | @@ -523,32 +534,29 @@ extensions. This is supported as shown by the following table (from-to): | _*.js_ | _js_ | | _*.json_ | _json_ | -**NOTE:** if you have files without an extension or e.g. _*.txt_ you _have_ to +**NOTE:** if you have files without an extension or e.g. _*.txt_ you _have_ to specify the origin or target type! ## API Usage Since the usage on CLI is a 2-step process: -1. Read from source file to JS object => -2. Write out (maybe to other type) +1. Read from source file to JS object ⇒ 2. Write out (maybe to other type) -the direct API calls additionally provide the usage of a _middleware_ function -where you can alter the input JS object before it is written and therefore, which turns +the direct API calls additionally provide the usage of a _middleware_ function +where you can alter the input JS object before it is written and therefore, which turns this into a 3-step process: - -1. Read from source => -2. Alter the JS object => -3. Write out (maybe to other type) -For more details about this and all the functions provided by this module please refer to the -[API Reference](https://github.com/deadratfink/jy-transform/wiki/API-v1.0). +1. Read from source ⇒ 2. Alter the JS object ⇒ 3. Write out (maybe to other type) + +For more details about this and all the functions provided by this module please refer to the +[API Reference](https://github.com/deadratfink/jy-transform/wiki/API-v2). The `origin` and `target` type inference is also standard for the API level. ### API Properties -The `Transformer` exposes the following function which takes besides an (optional) +The `Transformer` exposes the following function which takes besides an (optional) `middleware` function the necessary `options` for the transformation: ```javascript @@ -565,8 +573,8 @@ The `options` object has to follow this key-values table: | dest | string | Writable | object | The destination information object: `string` is used as file path, `Writable` stream writes a stringified source and `object` is used as direct JS object for assignment. | The output file is stored relative to the input file (same base name but with another extension if type differs). If input and output type are the same then the file overwriting is handled depending on the 'force' value! | no | | indent | number | The indention in files. | 4 | no | | force | boolean | Force overwriting of existing output files on write phase. When files are not overwritten, then the next transformation with same output file name gets a consecutive number on the base file name, e.g. in case of _foo.yaml_ it would be _foo(1).yaml_. | _false_ | no | -| imports | string | Define a 'module.exports[.identifier] = ' identifier (to read from JS _source_ only, must be a valid JS identifier!) | _undefined_ | no | -| exports | string | Define a 'module.exports[.identifier] = ' identifier (for usage in JS _destination_ only, must be a valid JS identifier!) | _undefined_ | no | +| imports | string | Define a `module.exports[.identifier] = ...` identifier (to read from JS _source_ only, must be a valid JS identifier!) | _undefined_ | no | +| exports | string | Define a `module.exports[.identifier] = ...` identifier (for usage in JS _destination_ only, must be a valid JS identifier!) | _undefined_ | no | **NOTE:** an invalid indention setting (1 > indent > 8) does not raise an error but a default of 4 SPACEs is applied instead. @@ -584,13 +592,13 @@ var options = { ### Using Middleware -The `middleware` is optional but if provided it must be of type `Function` and -a [Promise](http://bluebirdjs.com/docs/api-reference.html). One of the easiest -ones is the identity function +The `middleware` is optional but if provided it must be of type `Function` and +a [Promise](http://bluebirdjs.com/docs/api-reference.html). One of the easiest +ones is the identity function -_f(data) -> data_ +_f(data) → data_ -which could be expressed as +which could be expressed as [Promise](http://bluebirdjs.com/docs/api-reference.html) function as follows: ```javascript @@ -599,8 +607,8 @@ var identity = function (data) { } ``` -Of course, this would have no effect on the provided JS data. Actually, this one is -used internally when no middleware is provided to ensure the proper promised +Of course, this would have no effect on the provided JS data. Actually, this one is +used internally when no middleware is provided to ensure the proper promised control flow. OK, lets go back to a more practical example, e.g. we want to alter the value of @@ -615,7 +623,7 @@ Applying this [Promise](http://bluebirdjs.com/docs/api-reference.html) as middle ```javascript var middleware = function (data) { - data.foo = 'new bar'; + data.foo = 'new bar'; return Promise.resolve(data); } @@ -632,21 +640,21 @@ will result in such JSON file: ```javascript { - "foo": "new bar" + "foo": "new bar" } ``` -Of course, in real world scenarios you will have use cases which usually have a -higher complexity where one function might be insufficient or at least -inconvenient. but this does not raise a problem at all, because you can create -several functions to be applied in the whole transformation process by gathering +Of course, in real world scenarios you will have use cases which usually have a +higher complexity where one function might be insufficient or at least +inconvenient. but this does not raise a problem at all, because you can create +several functions to be applied in the whole transformation process by gathering them in one function. -Let's assume we have some Promise functions to apply. For simplicity reasons we -simulate these for the moment by two functions, each adding a key-value to the +Let's assume we have some Promise functions to apply. For simplicity reasons we +simulate these for the moment by two functions, each adding a key-value to the given (initially empty) JS object. -**NOTE:** each of them has to resolve with the `data` object! +**NOTE:** each of them has to resolve with the `data` object! ```javascript @@ -659,16 +667,21 @@ function key2(data) { objectPath.set(data, 'key2', 'value2'); return Promise.resolve(data); } + +function key3(data) { + objectPath.set(data, 'key3', 'value3'); + return Promise.resolve(data); +} ``` These can be collected by different aggregation or composition functions of the underlying -Promise framework, e.g. using the [`Promise.all([...])`](http://bluebirdjs.com/docs/api/promise.all.html) +Promise framework, e.g. using the [`Promise.all([...])`](http://bluebirdjs.com/docs/api/promise.all.html) function. This one can collect all three functions above and ensure their proper subsequent execution: - + ```javascript var middleware = function (data) { - return Promise.all([key1(data), key2(data)]) + return Promise.all([key1(data), key2(data), key3(data)]) .then(function(result) { return Promise.resolve(result[result.length - 1]); }); @@ -676,7 +689,9 @@ var middleware = function (data) { var transformer = new Transformer(logger); var logger = ...; -var options = {...}; +var options = { + src: {} +}; return transformer.transform(options, middleware) .then(function (msg){ @@ -687,19 +702,21 @@ return transformer.transform(options, middleware) }); ``` -Then the result in the `middleware` function can be retrieved from the returned -array, i.e. in case of [`Promise.all([...])`](http://bluebirdjs.com/docs/api/promise.all.html) -you have to pick the _last_ element which contains the "final product". -From our example above it would be +Then the result in the `middleware` function can be retrieved from the returned +array, i.e. in case of [`Promise.all([...])`](http://bluebirdjs.com/docs/api/promise.all.html) +you have to pick the _last_ element which contains the "final product". + +From our example above it would be result in this object ```javascript { key1: 'value1', - key2: 'value2' + key2: 'value2', + key3: 'value3' } ``` -which then is passed back to the transformation chain. Following this pattern +which then is passed back to the transformation chain. Following this pattern you can do almost everything with the JS object, like - deleting properties @@ -711,8 +728,8 @@ Whatever you do during transformation, just keep it valid ;-) ## Using Custom Logger -It is usual that you use an own `logger` in your application. This module supports you by -letting you inject your logger as constructor argument: the `Reader`, `Transformer` and +It is usual that you use an own `logger` in your application. This module supports you by +letting you inject your logger as constructor argument: the `Reader`, `Transformer` and `Writer` constructor will accept an (optional) logger object. If you do not provide one, then the default logger is `console`. @@ -725,59 +742,71 @@ var transformer = new Transformer(logger); var writer = new Writer(logger); ``` -At least, the passed logger object _has to_ support the following functions: +At least, the passed `logger` object _has_ to support the following functions: ```javascript function info(msg) function debug(msg) -function error(msg) +function trace(msg) +function error(err|msg) ``` +Anyway, there are some fallbacks if a level is not supported: + +- DEBUG ⇒ INFO +- TRACE ⇒ DEBUG # API Reference -For more details on how to use the API, please refer to the -[API Reference](https://github.com/deadratfink/jy-transform/wiki/API-v1.0) +For more details on how to use the API, please refer to the +[API Reference](https://github.com/deadratfink/jy-transform/wiki/API-v2) wiki which describes the full API and provides more examples. -# Changelog - -The complete changelog is listed in the wiki [Changelog](https://github.com/deadratfink/jy-transform/wiki/Changelog) section. +# Contributing +Pull requests and stars are always welcome. Anybody is invited to take part +into this project. For bugs and feature requests, please create an +[issue](https://github.com/deadratfink/jy-transform/issues). +See the wiki [Contributing](https://github.com/deadratfink/jy-transform/wiki/Changelog) +section for more details about conventions. -# Contributing -Pull requests and stars are always welcome. Anybody is invited to take part -into this project. For bugs and feature requests, please create an -[issue](https://github.com/deadratfink/jy-transform/issues). -When contributing as coder, please take care of the following conventions: - -- Enter yourself in the `constributors` section of _package.json_. -- We strictly follow [Semantic Versioning 2](http://semver.org) rules. -- The `development` branch is the leading branch and is protected. Create bugfix and feature - branches (or fork into you own namespace) and create pull - requests to `development` when finished. Any of these should be prefixed with - `bugfix/#...` or `feature/#...` (followed by issue number and a short, "underscored" - proper meaning), e.g. - - `bugfix/#8_fix_js_reading_with_require` - - `feature/#14_multidocument_support` -- Remember that name could need to be enclosed in quotes, e.g. - ```$ git checkout -b 'feature/#19_...'``` - when using git shell command. -- The `master` branch is protected and is the stable branch after a release. - It will never be pushed directly (only on release build). -- Indention for any file is 4 SPACEs. -- Keep code coverage high (> 95%). -- Doc everything with [JSDocs](http://usejsdoc.org/) and document concepts in - [README.md](https://github.com/deadratfink/jy-transform/blob/development/README.md) - or [Wiki](https://github.com/deadratfink/jy-transform/wiki). -- Use single parenthesis (`'...'`) in _*.js_ files instead of double parenthesis (`"..."`). -- Avoid the of use parenthesis for keys in JSON objects. -- Use the strict mode (`'use strict';`) in _*.js_ files. -- File names should be lower-case with hyphens as divider, e.g. _options-handler.js_. -- Markdown documentation files should be upper-case with _.md_ as extension, placed - in _./docs_, e.g. _USAGE.md_. The _README.md_ is build up by these files concatenated - by `npm run docs` command. Any new files have to be added to `scripts.docs` section of - _package.json_. Don't forget to regenerate _README.md_ before committing. +# Changelog +### v2.0.0 + + +- [[#33](https://github.com/deadratfink/jy-transform/issues/33)] Enhance `LogWrapper` with `TRACE` level (API) +- [[#32](https://github.com/deadratfink/jy-transform/issues/32)] Introduce input and output on CLI as ARGS instead of OPTIONS (non-backwards compatible change for CLI usage, _no_ impact on API level!) + - e.g. on CLI type in `$ jyt foo.js bar.yaml` instead of `$ jyt -s foo.js -d bar.yaml` +- [[#31](https://github.com/deadratfink/jy-transform/issues/31)] Bugfix: given `Object` source results in 'yaml' for origin (API) +- [Cleanup] Update dependencies + +### v1.0.2 + +- [[#30](https://github.com/deadratfink/jy-transform/issues/30)] Fix README and externalize API reference to wiki +- [[#29](https://github.com/deadratfink/jy-transform/issues/29)] Fix Promise warning on write process + +### v1.0.1 + +Initial public release. This covers the basic implementation and tests. The following features and fixes and part of this release: + +- [[#27](https://github.com/deadratfink/jy-transform/issues/27)] Export variable for JS input +- [[#22](https://github.com/deadratfink/jy-transform/issues/22)] Integrate Coveralls +- [[#21](https://github.com/deadratfink/jy-transform/issues/21)] Check and fix CodeClimate issues +- [[#20](https://github.com/deadratfink/jy-transform/issues/20)] Cleanup test dir +- [[#19](https://github.com/deadratfink/jy-transform/issues/19)] File overwrite switch (`-f`, `-force`) +- [[#18](https://github.com/deadratfink/jy-transform/issues/18)] Read and Write from other sources than file path +- [[#16](https://github.com/deadratfink/jy-transform/issues/16)] ERROR: Error: Invalid target option found while creating destination file extension +- [[#15](https://github.com/deadratfink/jy-transform/issues/15)] Measure test code coverage and add a badge +- [[#12](https://github.com/deadratfink/jy-transform/issues/12)] Create middleware collection file to use by clients and internally +- [[#11](https://github.com/deadratfink/jy-transform/issues/11)] Check all Promises for optimization possibilities +- [[#10](https://github.com/deadratfink/jy-transform/issues/10)] Integrate project with Travis +- [[#9](https://github.com/deadratfink/jy-transform/issues/9)] Resolve origin and target from file extension whenever possible +- [[#8](https://github.com/deadratfink/jy-transform/issues/8)] Enable JS reading with `require(...)` +- [[#7](https://github.com/deadratfink/jy-transform/issues/7)] YAML indent is not set to `Constants.MIN_YAML_INDENT` when indent is set to 0 +- [[#6](https://github.com/deadratfink/jy-transform/issues/6)] Finish full JSDoc for all methods +- [[#5](https://github.com/deadratfink/jy-transform/issues/5)] Write unit tests +- [[#4](https://github.com/deadratfink/jy-transform/issues/4)] Export variable for JS output +- [[#3](https://github.com/deadratfink/jy-transform/issues/3)] Promise array as middleware solved with `Promise.all([...])` diff --git a/VERSION.txt b/VERSION.txt new file mode 100644 index 0000000..21e8796 --- /dev/null +++ b/VERSION.txt @@ -0,0 +1 @@ +1.0.3 diff --git a/bin/test.sh b/bin/test.sh new file mode 100644 index 0000000..1a11dad --- /dev/null +++ b/bin/test.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +TMP=bin/tmp/ +PREPARE_LOG=bin/tmp/release-prepare.log +file="VERSION.txt" +VERSION=$(cat "$file") +current=$(pwd) +echo -e $current +echo -e "Release prepare: $VERSION" +BIN=bin/prepare-release.sh + +if [ ! -d "$TMP" ]; then + mkdir bin/tmp/ +else + rm -Rf bin/tmp/ + mkdir bin/tmp/ +fi + +#git reset --hard +#git checkout --track origin/master +#git checkout --track origin/development +#export GIT_MERGE_AUTOEDIT=no +#git config gitflow.branch.develop development +#git config gitflow.prefix.versiontag v +#git flow init -fd +#git flow release start $VERSION +#npm --no-git-tag-version version $VERSION +#json -I -o json-4 -f package.json +#git commit -am 'Published $VERSION release branch' +#git flow release publish $VERSION diff --git a/docs/BADGES.md b/docs/BADGES.md index f8a311f..7262b7b 100644 --- a/docs/BADGES.md +++ b/docs/BADGES.md @@ -1,21 +1,33 @@ # Stats -| [Github License](https://github.com/deadratfink/jy-transform/blob/master/LICENSE.md) | [Github Issues](https://github.com/deadratfink/jy-transform/issues) | [Github Release](https://github.com/deadratfink/jy-transform/releases) | [Github Tags](https://github.com/deadratfink/jy-transform/tags) | [Travis CI](https://travis-ci.org) | [Waffle](https://waffle.io/deadratfink/jy-transform) | [Code Climate](https://codeclimate.com/github/deadratfink/jy-transform) | +## General + +| [License](https://github.com/deadratfink/jy-transform/blob/master/LICENSE.md) | [Issues](https://github.com/deadratfink/jy-transform/issues) | [Releases](https://github.com/deadratfink/jy-transform/releases) | [Tags](https://github.com/deadratfink/jy-transform/tags) | [Travis CI](https://travis-ci.org) | [Waffle](https://waffle.io/deadratfink/jy-transform) | [Code Climate](https://codeclimate.com/github/deadratfink/jy-transform) | | --- | --- | --- | --- | --- | --- | --- | -| [![License][gh-license-image]][gh-license-url] | [![Issue Stats][gh-issues-image]][gh-issues-url] | [![Github Releases][gh-releases-image]][gh-releases-url] | [![Github Tags][gh-tags-image]][gh-tags-url] | [![Build Status][ci-image]][ci-url] | [![Waffle][waffle-image]][waffle-url] | [![Code Climate][cocl-image]][cocl-url] | +| [![License][gh-license-image]][gh-license-url] | [![Issue Stats][gh-issues-image]][gh-issues-url] | [![Releases][gh-releases-image]][gh-releases-url] | [![Tags][gh-tags-image]][gh-tags-url] | [![Build Status][ci-image]][ci-url] | [![Waffle][waffle-image]][waffle-url] | [![Code Climate][cocl-image]][cocl-url] | + +## Branches | Branch | [Codecov](https://codecov.io) | [Coveralls](https://coveralls.io) | [Inch CI](http://inch-ci.org) | [David](https://david-dm.org) DM | [David](https://david-dm.org) DM (dev) | | --- | --- | --- | --- | --- | --- | | master | [![codecov.io][cc-image-master]][cc-url-master] | [![coveralls.io][ca-image-master]][ca-url-master] | [![inch-ci.org][inch-image-master]][inch-url-master] | [![Dependency Status][dep-image-master]][dep-url-master] | [![devDependency Status][devdep-image-master]][devdep-url-master] | | development | [![codecov.io][cc-image-development]][cc-url-development] | [![coveralls.io][ca-image-development]][ca-url-development] | [![inch-ci.org][inch-image-development]][inch-url-development] | [![Dependency Status][dep-image-development]][dep-url-development] | [![devDependency Status][devdep-image-development]][devdep-url-development] | -## Coverage Graphs +### Coverage -| Branch | Graph | +| master | development | | --- | --- | -| master | ![codecov.io](https://codecov.io/github/deadratfink/jy-transform/branch.svg?branch=master&vg=true) | -| development| ![codecov.io](https://codecov.io/github/deadratfink/jy-transform/branch.svg?branch=development&vg=true) | +| ![codecov.io](https://codecov.io/gh/deadratfink/jy-transform/branch/master/graphs/tree.svg) | ![codecov.io](https://codecov.io/gh/deadratfink/jy-transform/branch/development/graphs/tree.svg) | + + + + + + +## NPM +[![NPM](https://nodei.co/npm/jy-transform.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/jy-transform/) +[![NPM](https://nodei.co/npm-dl/jy-transform.png?height=3&months=9)](https://nodei.co/npm-dl/jy-transform/) [gh-license-image]: https://img.shields.io/github/license/deadratfink/jy-transform.svg?style=flat-square [gh-license-url]: https://github.com/deadratfink/jy-transform/blob/master/LICENSE.md diff --git a/CHANGELOG.md b/docs/CHANGELOG.md similarity index 73% rename from CHANGELOG.md rename to docs/CHANGELOG.md index a7bb3bf..32e8c89 100644 --- a/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,11 +1,22 @@ +# Changelog + +### v2.0.0 + + +- [[#33](https://github.com/deadratfink/jy-transform/issues/33)] Enhance `LogWrapper` with `TRACE` level (API) +- [[#32](https://github.com/deadratfink/jy-transform/issues/32)] Introduce input and output on CLI as ARGS instead of OPTIONS (non-backwards compatible change for CLI usage, _no_ impact on API level!) + - e.g. on CLI type in `$ jyt foo.js bar.yaml` instead of `$ jyt -s foo.js -d bar.yaml` +- [[#31](https://github.com/deadratfink/jy-transform/issues/31)] Bugfix: given `Object` source results in 'yaml' for origin (API) +- [Cleanup] Update dependencies + ### v1.0.2 -- [[#30](https://github.com/deadratfink/jy-transform/issues/30)] Fix README and externalize API Reference to wiki +- [[#30](https://github.com/deadratfink/jy-transform/issues/30)] Fix README and externalize API reference to wiki - [[#29](https://github.com/deadratfink/jy-transform/issues/29)] Fix Promise warning on write process ### v1.0.1 -Initial release. This covers the basic implementation and tests. The following features and fixes and part of this release: +Initial public release. This covers the basic implementation and tests. The following features and fixes and part of this release: - [[#27](https://github.com/deadratfink/jy-transform/issues/27)] Export variable for JS input - [[#22](https://github.com/deadratfink/jy-transform/issues/22)] Integrate Coveralls diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 6175669..f99835c 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -1,11 +1,8 @@ # Contributing -Pull requests and stars are always welcome. Anybody is invited to take part -into this project. For bugs and feature requests, please create an -[issue](https://github.com/deadratfink/jy-transform/issues). When contributing as coder, please take care of the following conventions: -- Enter yourself in the `constributors` section of _package.json_. +- Enter yourself in the `contributors` section of _package.json_. - We strictly follow [Semantic Versioning 2](http://semver.org) rules. - The `development` branch is the leading branch and is protected. Create bugfix and feature branches (or fork into you own namespace) and create pull @@ -24,12 +21,13 @@ When contributing as coder, please take care of the following conventions: - Doc everything with [JSDocs](http://usejsdoc.org/) and document concepts in [README.md](https://github.com/deadratfink/jy-transform/blob/development/README.md) or [Wiki](https://github.com/deadratfink/jy-transform/wiki). -- Use single parenthesis (`'...'`) in _*.js_ files instead of double parenthesis (`"..."`). +- Use _single_ parenthesis (`'...'`) in _*.js_ files instead of _double_ parenthesis (`"..."`). - Avoid the of use parenthesis for keys in JSON objects. - Use the strict mode (`'use strict';`) in _*.js_ files. - File names should be lower-case with hyphens as divider, e.g. _options-handler.js_. - Markdown documentation files should be upper-case with _.md_ as extension, placed in _./docs_, e.g. _USAGE.md_. The _README.md_ is build up by these files concatenated by `npm run docs` command. Any new files have to be added to `scripts.docs` section of - _package.json_. Don't forget to regenerate _README.md_ before committing. + _package.json_. Don't forget to regenerate _README.md_ (`$ npm run docs`) and wiki + (`$ npm run wiki`) before committing. diff --git a/docs/LOGO.md b/docs/LOGO.md new file mode 100644 index 0000000..cbb067c --- /dev/null +++ b/docs/LOGO.md @@ -0,0 +1,2 @@ +![jy-transform logo](https://github.com/deadratfink/jy-transform/blob/master/image/jytransform.png) + diff --git a/docs/USAGE.md b/docs/USAGE.md index 748650c..7079e95 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -1,14 +1,14 @@ ## Motivation -Why this module? After struggling with some huge YAML file and accidentally -occurring wrong indentions which results in an annoying failure investigation, -I decided to get rid of the YAML file and therefore, create a module which -should be aimed as the swiss army knife for transforming YAML, JS and JSON +Why this module? After struggling with some huge YAML file and accidentally +occurring wrong indentions which results in an annoying failure investigation, +I decided to get rid of the YAML file and therefore, create a module which +should be aimed as the swiss army knife for transforming YAML, JS and JSON types into each other format. # Usage -The module can be used on CLI or as API (the latter is fully [Promise](http://bluebirdjs.com/docs/api-reference.html) +The module can be used on CLI or as API (the latter is fully [Promise](http://bluebirdjs.com/docs/api-reference.html) based). ## Usage Types @@ -38,34 +38,37 @@ Reading from: - _*.js_ file - _*.json_ file -Additionally, on API level: +Additionally, on API level to a: -- `stream.Readable` (requires `options.origin` property set, reads as UTF-8) -- any JS `object` (actually, this means the reading phase is skipped, because object is in-memory already) +- `stream.Readable` + - Serialized JSON and YAML + - Requires `options.origin` property set + - Reads as UTF-8 +- JS `object` (actually, this means the reading phase is skipped, because object is in-memory already) ### Transformation The transformation can take place into several directions: -- YAML => JS -- YAML => JSON -- JS => YAML -- JSON => YAML -- JS => JSON -- JSON => JS -- YAML => YAML -- JSON => JSON -- JS => JS +- YAML ⇒ JS +- YAML ⇒ JSON +- JS ⇒ YAML +- JSON ⇒ YAML +- JS ⇒ JSON +- JSON ⇒ JS +- YAML ⇒ YAML +- JSON ⇒ JSON +- JS ⇒ JS while: - [YAML](http://http://yaml.org/) = _*.yaml_, _*.yml_ -- [JS](https://developer.mozilla.org/en-US/docs/Web/JavaScript) = _*.js_ (JS object) +- [JS](https://developer.mozilla.org/en-US/docs/Web/JavaScript) = _*.js_ (JS object) - [JSON](http://json.org) = _*.json_ (JS object serialized as JSON) ### Middleware -Apply actions on the intermediate JS object via injected [Promise](http://bluebirdjs.com/docs/api-reference.html) +Apply actions on the intermediate JS object via injected [Promise](http://bluebirdjs.com/docs/api-reference.html) functions. This is an optional part for [transformation](#transformation) phase. ### Writing @@ -76,14 +79,17 @@ Writing to: - _*.js_ file - _*.json_ file -Additionally, on API level: +Additionally, on API level to a: -- `stream.Writable` (requires `options.target` property set, writes UTF-8) -- any JS `object` +- `stream.Writable` + - Serialized JS, JSON and YAML + - Requires `options.target` property set + - Writes UTF-8 +- JS `object` ## Limitations -- Since this module is build to transform from and to different type formats, any +- Since this module is build to transform from and to different type formats, any `Function`s residing in JS type objects are _not_ supported, e.g. transforming ```javascript module.exports = { @@ -91,83 +97,75 @@ Additionally, on API level: fooFunction: foo() {...} } ``` - to JSON would simply result in + to JSON would simply result in ```javascript { fooKey: 'foo' } ``` - while transforming to YAML type would even result in an `Error`, e.g. printed + while transforming to YAML type would even result in an `Error`, e.g. printed on CLI usage like this: ``` ERROR: YAMLException: unacceptable kind of an object to dump [object Function] ``` -- Multidocument handling would be a cool feature which refers in general to YAML - and JS only, but at the moment we require that each document to transform is a - _single_ one per source (or in case of JS could be identified)! This feature is +- Multidocument handling would be a cool feature which refers in general to YAML + and JS only, but at the moment we require that each document to transform is a + _single_ one per source (or in case of JS could be identified)! This feature is planned and reflected in [#14](https://github.com/deadratfink/jy-transform/issues/14). -- Schema validation for input and output is another topic which is planned by - [#1](https://github.com/deadratfink/jy-transform/issues/1) and +- Schema validation for input and output is another topic which is planned by + [#1](https://github.com/deadratfink/jy-transform/issues/1) and [#2](https://github.com/deadratfink/jy-transform/issues/2). ## CLI Usage -The CLI provides the `jyt` command (actually, this requires the use of options). -After the global installation you can access the `Transformer` command options -with the usual help command as follows: - -``` -$ jyt --help -``` - -### CLI Options - -The `--help` option prints an overview about all available CLI properties: +The CLI provides the `jyt` command (actually, this requires the use of options). +After the global installation you can access the `Transformer` command options +with the usual command option `--help` option which prints an overview about all +available CLI properties: ``` $ jyt --help Usage: - jyt [OPTIONS] - -Options: - -o, --origin [STRING] The conversion origin: [ js | json | yaml ]. (Default is : if not given, the type is tried to be inferred from the extension of source path, else it is yaml) - -t, --target [STRING] The conversion target: [ js | json | yaml ]. (Default is : if not given, the type is tried to be inferred from the extension of destination path, else it is js) - -s, --src PATH The absolute/relative input file path. - -d, --dest [PATH] The absolute/relative output file path. When this - options is ommited then the output file is stored - relative to the input file (same base name but with - another extension if type differs). If input and - output type are the same then the file overwriting is - handled depending on the '--force' value! (Default is storing relative to input file) - -i, --indent [NUMBER] The indention for pretty-print: 1 - 8. (Default is 4) - -f, --force Force overwriting of existing output files on write - phase. When files are not overwritten (which is - default), then the next transformation with same - output file name gets a consecutive number on the base - file name, e.g. in case of foo.yaml it would be - foo(1).yaml. - -m, --imports STRING Define a 'module.exports[.identifier] = ' - identifier (to read from JS _source_ file only, must - be a valid JS identifier!). - -x, --exports STRING Define a 'module.exports[.identifier] = ' - identifier, for usage in JS destination file only, - must be a valid JS identifier! + jyt INPUT-FILE [OUTPUT-FILE] [OPTIONS] + +Options: + -o, --origin [STRING] The origin type of INPUT-FILE: [ js | json | yaml ]. (Default is if not given, the type is tried to be inferred from the extension of source path, else it is 'yaml') + -t, --target [STRING] The target type of OUTPUT-FILE: [ js | json | yaml ]. (Default is if not given, the type is tried to be inferred from the extension of destination path, else it is 'js') + -i, --indent [NUMBER] The indention for pretty-print: 1 - 8. (Default is 4) + -f, --force Force overwriting of existing output files on write phase. When files are not overwritten (which is default), + then the next transformation with same output file name gets a consecutive number on the base file name, e.g. in + case of foo.yaml it would be foo(1).yaml. + -m, --imports STRING Define a 'module.exports[.identifier] = ' identifier (to read from JS _source_ file only, must be a valid JS + identifier!). + -x, --exports STRING Define a 'module.exports[.identifier] = ' identifier (for usage in JS destination file only, must be a valid JS + identifier!). -k, --no-color Omit color from output --debug Show debug information -v, --version Display the current version -h, --help Display help and usage details ``` -These are more formally defined in the following table: +### CLI Args + +The ARGS are more formally defined in the following table: + +| Arg | Type | Description | Default | Required | +| --- | --- | --- | --- | --- | +| `INPUT-FILE` | URI | The source file path for transformation. | - | yes | +| `OUTPUT-FILE` | URI | The destination file path to transform to. | When this options is omitted then the output file is stored relative to the input file (same base name but with another extension if type differs). If input and output type are the same then the file overwriting is handled depending on the `--force` value! | no | + +**NOTE:** the input file has to be specified and should _first_ argument (in fact, it can be anywhere but it must be before an out file argument)! + +### CLI Options + +The OPTIONS are more formally defined in the following table: | Option (short) | Option (long) | Type | Description | Default | Required | | --- | --- | --- | --- | --- | --- | -| `-o` | `--origin` | [ _js_ | _json_ | _yaml_ ] | The transformation origin type. | if not given, the type is tried to be inferred from the extension of source path, else it is _yaml_ | no | -| `-t` | `--target` | [ _js_ | _json_ | _yaml_ ] | The transformation target type. | if not given, the type is tried to be inferred from the extension of destination path, else it is _js_ | no | -| `-s` | `--src` | URI | The source file path for transformation. | - | yes | -| `-d` | `--dest` | URI | The destination file path to transform to. | When this options is ommited then the output file is stored relative to the input file (same base name but with another extension if type differs). If input and output type are the same then the file overwriting is handled depending on the `--force` value! | no | -| `-i` | `--indent` | integer
- [ 1 - 8 ]
| The code indention used in destination files. | 4 | no | -| `-f` | `--force` | n/a | Force overwriting of existing output files on write phase. When files are not overwritten (which is default), then the next transformation with same output file name gets a consecutive number on the base file name, e.g. in case of foo.yaml it would be foo(1).yaml. | _false_ | no | +| `-o` | `--origin` | string of: [ _js_ | _json_ | _yaml_ ] | The transformation origin type. | if not given, the type is tried to be inferred from the extension of source path, else it is _yaml_ | no | +| `-t` | `--target` | string of: [ _js_ | _json_ | _yaml_ ] | The transformation target type. | if not given, the type is tried to be inferred from the extension of destination path, else it is _js_ | no | +| `-i` | `--indent` | integer
[ 1 - 8 ]
| The code indention used in destination files. | 4 | no | +| `-f` | `--force` | n/a | Force overwriting of existing output files on write phase. When files are not overwritten (which is default), then the next transformation with same output file name gets a consecutive number on the base file name, e.g. in case of _foo.yaml_ it would be _foo(1).yaml_. | _false_ | no | | `-m` | `--imports` | string | Define a 'module.exports[.identifier] = ' identifier (to read from JS _source_ file only, must be a valid JS identifier!) | _undefined_ | no | | `-x` | `--exports` | string | Define a 'module.exports[.identifier] = ' identifier (for usage in JS _destination_ file only, must be a valid JS identifier!) | _undefined_ | no | | `-k` | `--no-color` | n/a | Omit color from output. | _color_ | no | @@ -176,18 +174,17 @@ These are more formally defined in the following table: | `-h` | `--help` | n/a | Display help and usage details. | n/a | no | - **NOTE:** an invalid indention setting (1 > `-i`, `--indent` > 8) does not raise an error but a default of 4 SPACEs is applied instead. ### Examples -Now we know which properties we can apply on CLI, so let's assume we +Now we know which properties we can apply on CLI, so let's assume we have a YAML file located in _foo.yaml_ holding this data: ```yaml foo: bar ``` -#### Example: YAML => JSON +#### Example: YAML ⇒ JSON then we can transform it to a JSON file _foo.json_ @@ -200,29 +197,29 @@ then we can transform it to a JSON file _foo.json_ using this command: ``` -$ jyt -s foo.yaml -t json -i 2 +$ jyt foo.yaml -t json -i 2 ``` -In this example we have overwritten the standard target type (which is `js`) -and applying an indent of _2_ instead of the default _4_. As default the output -file _foo.json_ is written relative to the input file (simply omitting the +In this example we have overwritten the standard target type (which is `js`) +and applying an indent of 2 instead of the default 4. As default the output +file _foo.json_ is written relative to the input file (simply omitting the `dest` option here). -**NOTE:** here you _have_ to provide the target with `-t json` or else the -default `js` would have been applied! If the source would have been a `js` +**NOTE:** here you _have_ to provide the target with `-t json` or else the +default `js` would have been applied! If the source would have been a `js` type like ``` -$ jyt -s foo.js -t json -i 2 +$ jyt foo.js -t json -i 2 ``` -then the `js` value for `origin` is automatically inferred from file extension. +then the `js` value for `origin` is automatically inferred from file extension. Accordingly, this is also true for the `target` option. -#### Example: JSON => JS +#### Example: JSON ⇒ JS ``` -$ jyt -s foo.json -i 2 +$ jyt foo.json -i 2 ``` ```javascript module.exports = { @@ -230,10 +227,10 @@ module.exports = { } ``` -#### Example: JS => YAML +#### Example: JS ⇒ YAML ``` -$ jyt -s foo.js -t yaml +$ jyt foo.js -t yaml ``` ```yaml foo: bar @@ -241,27 +238,27 @@ foo: bar #### Example: Transformation with Different Destination -Simply provide the `-d` with a different file name: +Simply specify the _output_ file with a different file name: ``` -$ jyt -s foo.json -d results/foobar.yaml +$ jyt foo.json results/foobar.yaml ``` #### Example: Transformation with Unsupported Source File Extension -As said, normally we infer from file extension to the type but assume the source -file has a file name which does not imply the type (here JS -type in a TEXT file), then you can simply provide the `-o` option with the +As said, normally we infer from file extension to the type but assume the source +file has a file name which does not imply the type (here a JSON +type in a TEXT file), then you can simply provide the `-o` option with the correct `origin` type (of course, the `-t` option works analogous): ``` -$ jyt -s foo.txt -o js -d foobar.yaml +$ jyt foo.txt foobar.yaml -o json ``` #### Example: Read from File with Exports Identifier -It could be that a JS source `exports` several objects and you want to read +It could be that a JS source `exports` several objects and you want to read from exactly the one you specify, then provide the `-m` (`--imports`) option. In this this example we have a _foo.js_ file exporting _two_ objects: @@ -279,7 +276,7 @@ module.exports.bar = { but you want to convert `bar` object, then call: ``` -$ jyt -s foo.js -m bar -d bar.yaml +$ jyt foo.js bar.yaml -m bar ``` to get the YAML result: @@ -317,8 +314,8 @@ as sub-node of `options.dest`. #### Example: Write Exports Identifier for JS File -Assume you want to generate a JS file with an exports string which gets an -identifier. We reuse the YAML file from above +Assume you want to generate a JS file with an exports string which gets an +identifier. We reuse the YAML file from above ```yaml foo: bar @@ -327,7 +324,7 @@ foo: bar using this command: ``` -$ jyt -s foo.yaml -d foobar.js -x foobar +$ jyt foo.yaml foobar.js -x foobar ``` This generates the following output in JS file using `foobar` as identifier: @@ -339,33 +336,33 @@ module.exports.foobar = { ``` **NOTE:** the identifier must be a valid JS identifier accoding to ECMAScript 6 -(see also [Valid JavaScript variable names in ECMAScript 6](https://mathiasbynens.be/notes/javascript-identifiers-es6) +(see also [Valid JavaScript variable names in ECMAScript 6](https://mathiasbynens.be/notes/javascript-identifiers-es6) and [Generating a regular expression to match valid JavaScript identifiers](https://mathiasbynens.be/demo/javascript-identifier-regex)). #### Example: Force Overwriting -**IMPORTANT NOTE:** when using this feature then any subsequent -execution which uses the same target/file name, +**IMPORTANT NOTE:** when using this feature then any subsequent +execution which uses the same target/file name, will overwrite the original source or target created beforehand! -By default this feature is not enabled to prevent you from accidentally +By default this feature is not enabled to prevent you from accidentally overwriting your input source or already generated targets. -But let's say we want to overwrite the original source now because you want +But let's say we want to overwrite the original source now because you want to change the indention from 2 to 4 SPACEs, then we can do this as follows: ``` -$ jyt -s foo.js -f -``` +$ jyt foo.js -f +``` -Of course, leaving out the `-f` switch creates a new file relatively to -the `origin`, named as _foo(1).js_ (note the consecutive number). Naturally, -another run of the command would result int a file called _foo(2).js_ +Of course, leaving out the `-f` switch creates a new file relatively to +the `origin`, named as _foo(1).js_ (note the consecutive number). Naturally, +another run of the command would result in a file called _foo(2).js_ and so forth. ## Origin and Target Type Inference -The examples above have shown that we have an automatic type inference from file +The examples above have shown that we have an automatic type inference from file extensions. This is supported as shown by the following table (from-to): | File Extension | Type | @@ -375,32 +372,29 @@ extensions. This is supported as shown by the following table (from-to): | _*.js_ | _js_ | | _*.json_ | _json_ | -**NOTE:** if you have files without an extension or e.g. _*.txt_ you _have_ to +**NOTE:** if you have files without an extension or e.g. _*.txt_ you _have_ to specify the origin or target type! ## API Usage Since the usage on CLI is a 2-step process: -1. Read from source file to JS object => -2. Write out (maybe to other type) +1. Read from source file to JS object ⇒ 2. Write out (maybe to other type) -the direct API calls additionally provide the usage of a _middleware_ function -where you can alter the input JS object before it is written and therefore, which turns +the direct API calls additionally provide the usage of a _middleware_ function +where you can alter the input JS object before it is written and therefore, which turns this into a 3-step process: - -1. Read from source => -2. Alter the JS object => -3. Write out (maybe to other type) -For more details about this and all the functions provided by this module please refer to the -[API Reference](https://github.com/deadratfink/jy-transform/wiki/API-v1.0). +1. Read from source ⇒ 2. Alter the JS object ⇒ 3. Write out (maybe to other type) + +For more details about this and all the functions provided by this module please refer to the +[API Reference](https://github.com/deadratfink/jy-transform/wiki/API-v2). The `origin` and `target` type inference is also standard for the API level. ### API Properties -The `Transformer` exposes the following function which takes besides an (optional) +The `Transformer` exposes the following function which takes besides an (optional) `middleware` function the necessary `options` for the transformation: ```javascript @@ -417,8 +411,8 @@ The `options` object has to follow this key-values table: | dest | string | Writable | object | The destination information object: `string` is used as file path, `Writable` stream writes a stringified source and `object` is used as direct JS object for assignment. | The output file is stored relative to the input file (same base name but with another extension if type differs). If input and output type are the same then the file overwriting is handled depending on the 'force' value! | no | | indent | number | The indention in files. | 4 | no | | force | boolean | Force overwriting of existing output files on write phase. When files are not overwritten, then the next transformation with same output file name gets a consecutive number on the base file name, e.g. in case of _foo.yaml_ it would be _foo(1).yaml_. | _false_ | no | -| imports | string | Define a 'module.exports[.identifier] = ' identifier (to read from JS _source_ only, must be a valid JS identifier!) | _undefined_ | no | -| exports | string | Define a 'module.exports[.identifier] = ' identifier (for usage in JS _destination_ only, must be a valid JS identifier!) | _undefined_ | no | +| imports | string | Define a `module.exports[.identifier] = ...` identifier (to read from JS _source_ only, must be a valid JS identifier!) | _undefined_ | no | +| exports | string | Define a `module.exports[.identifier] = ...` identifier (for usage in JS _destination_ only, must be a valid JS identifier!) | _undefined_ | no | **NOTE:** an invalid indention setting (1 > indent > 8) does not raise an error but a default of 4 SPACEs is applied instead. @@ -436,13 +430,13 @@ var options = { ### Using Middleware -The `middleware` is optional but if provided it must be of type `Function` and -a [Promise](http://bluebirdjs.com/docs/api-reference.html). One of the easiest -ones is the identity function +The `middleware` is optional but if provided it must be of type `Function` and +a [Promise](http://bluebirdjs.com/docs/api-reference.html). One of the easiest +ones is the identity function -_f(data) -> data_ +_f(data) → data_ -which could be expressed as +which could be expressed as [Promise](http://bluebirdjs.com/docs/api-reference.html) function as follows: ```javascript @@ -451,8 +445,8 @@ var identity = function (data) { } ``` -Of course, this would have no effect on the provided JS data. Actually, this one is -used internally when no middleware is provided to ensure the proper promised +Of course, this would have no effect on the provided JS data. Actually, this one is +used internally when no middleware is provided to ensure the proper promised control flow. OK, lets go back to a more practical example, e.g. we want to alter the value of @@ -467,7 +461,7 @@ Applying this [Promise](http://bluebirdjs.com/docs/api-reference.html) as middle ```javascript var middleware = function (data) { - data.foo = 'new bar'; + data.foo = 'new bar'; return Promise.resolve(data); } @@ -484,21 +478,21 @@ will result in such JSON file: ```javascript { - "foo": "new bar" + "foo": "new bar" } ``` -Of course, in real world scenarios you will have use cases which usually have a -higher complexity where one function might be insufficient or at least -inconvenient. but this does not raise a problem at all, because you can create -several functions to be applied in the whole transformation process by gathering +Of course, in real world scenarios you will have use cases which usually have a +higher complexity where one function might be insufficient or at least +inconvenient. but this does not raise a problem at all, because you can create +several functions to be applied in the whole transformation process by gathering them in one function. -Let's assume we have some Promise functions to apply. For simplicity reasons we -simulate these for the moment by two functions, each adding a key-value to the +Let's assume we have some Promise functions to apply. For simplicity reasons we +simulate these for the moment by two functions, each adding a key-value to the given (initially empty) JS object. -**NOTE:** each of them has to resolve with the `data` object! +**NOTE:** each of them has to resolve with the `data` object! ```javascript @@ -511,16 +505,21 @@ function key2(data) { objectPath.set(data, 'key2', 'value2'); return Promise.resolve(data); } + +function key3(data) { + objectPath.set(data, 'key3', 'value3'); + return Promise.resolve(data); +} ``` These can be collected by different aggregation or composition functions of the underlying -Promise framework, e.g. using the [`Promise.all([...])`](http://bluebirdjs.com/docs/api/promise.all.html) +Promise framework, e.g. using the [`Promise.all([...])`](http://bluebirdjs.com/docs/api/promise.all.html) function. This one can collect all three functions above and ensure their proper subsequent execution: - + ```javascript var middleware = function (data) { - return Promise.all([key1(data), key2(data)]) + return Promise.all([key1(data), key2(data), key3(data)]) .then(function(result) { return Promise.resolve(result[result.length - 1]); }); @@ -528,7 +527,9 @@ var middleware = function (data) { var transformer = new Transformer(logger); var logger = ...; -var options = {...}; +var options = { + src: {} +}; return transformer.transform(options, middleware) .then(function (msg){ @@ -539,19 +540,21 @@ return transformer.transform(options, middleware) }); ``` -Then the result in the `middleware` function can be retrieved from the returned -array, i.e. in case of [`Promise.all([...])`](http://bluebirdjs.com/docs/api/promise.all.html) -you have to pick the _last_ element which contains the "final product". -From our example above it would be +Then the result in the `middleware` function can be retrieved from the returned +array, i.e. in case of [`Promise.all([...])`](http://bluebirdjs.com/docs/api/promise.all.html) +you have to pick the _last_ element which contains the "final product". + +From our example above it would be result in this object ```javascript { key1: 'value1', - key2: 'value2' + key2: 'value2', + key3: 'value3' } ``` -which then is passed back to the transformation chain. Following this pattern +which then is passed back to the transformation chain. Following this pattern you can do almost everything with the JS object, like - deleting properties @@ -563,8 +566,8 @@ Whatever you do during transformation, just keep it valid ;-) ## Using Custom Logger -It is usual that you use an own `logger` in your application. This module supports you by -letting you inject your logger as constructor argument: the `Reader`, `Transformer` and +It is usual that you use an own `logger` in your application. This module supports you by +letting you inject your logger as constructor argument: the `Reader`, `Transformer` and `Writer` constructor will accept an (optional) logger object. If you do not provide one, then the default logger is `console`. @@ -577,21 +580,30 @@ var transformer = new Transformer(logger); var writer = new Writer(logger); ``` -At least, the passed logger object _has to_ support the following functions: +At least, the passed `logger` object _has_ to support the following functions: ```javascript function info(msg) function debug(msg) -function error(msg) +function trace(msg) +function error(err|msg) ``` +Anyway, there are some fallbacks if a level is not supported: + +- DEBUG ⇒ INFO +- TRACE ⇒ DEBUG # API Reference -For more details on how to use the API, please refer to the -[API Reference](https://github.com/deadratfink/jy-transform/wiki/API-v1.0) +For more details on how to use the API, please refer to the +[API Reference](https://github.com/deadratfink/jy-transform/wiki/API-v2) wiki which describes the full API and provides more examples. -# Changelog +# Contributing -The complete changelog is listed in the wiki [Changelog](https://github.com/deadratfink/jy-transform/wiki/Changelog) section. +Pull requests and stars are always welcome. Anybody is invited to take part +into this project. For bugs and feature requests, please create an +[issue](https://github.com/deadratfink/jy-transform/issues). +See the wiki [Contributing](https://github.com/deadratfink/jy-transform/wiki/Changelog) +section for more details about conventions. diff --git a/jyt b/jyt index ff7ba05..029ece4 100755 --- a/jyt +++ b/jyt @@ -18,7 +18,7 @@ var transformer = new Transformer(cli); * @type {string} * @private */ -var usage = path.basename(__filename) + ' [OPTIONS]'; +var usage = path.basename(__filename) + ' INPUT-FILE [OUTPUT-FILE] [OPTIONS]'; /** * The path to package.json. @@ -37,42 +37,73 @@ var packagePath = __dirname + '/package.json'; * @private */ var options = { - origin: [ 'o', 'The conversion origin: [ ' + constants.JS + ' | ' + constants.JSON + ' | ' + constants.YAML + ' ].', 'string', constants.DEFAULT_OPTIONS.origin ], - target: [ 't', 'The conversion target: [ ' + constants.JS + ' | ' + constants.JSON + ' | ' + constants.YAML + ' ].', 'string', constants.DEFAULT_OPTIONS.target ], - src: [ 's', 'The absolute/relative input file path.', 'path'], - dest: [ 'd', 'The absolute/relative output file path. When this options is ommited then the output file is stored relative to the input file (same base name but with another extension if type differs). If input and output type are the same then the file overwriting is handled depending on the \'--force\' value!', 'path', constants.DEFAULT_OPTIONS.dest], - indent: [ 'i', 'The indention for pretty-print: 1 - 8.', 'int', constants.DEFAULT_INDENT ], - force: [ 'f', 'Force overwriting of existing output files on write phase. When files are not overwritten (which is default), then the next transformation with same output file name gets a consecutive number on the base file name, e.g. in case of foo.yaml it would be foo(1).yaml.' ], - imports: [ 'm', 'Define a \'module.exports[.identifier] = \' identifier (to read from JS _source_ file only, must be a valid JS identifier!).', 'string', constants.DEFAULT_OPTIONS.imports ], - exports: [ 'x', 'Define a \'module.exports[.identifier] = \' identifier (for usage in JS destination file only, must be a valid JS identifier!).', 'string', constants.DEFAULT_OPTIONS.exports ] + origin: [ 'o', 'The origin type of INPUT-FILE: [ ' + constants.JS + ' | ' + constants.JSON + ' | ' + constants.YAML + ' ]', 'string', constants.DEFAULT_OPTIONS.origin ], + target: [ 't', 'The target type of OUTPUT-FILE: [ ' + constants.JS + ' | ' + constants.JSON + ' | ' + constants.YAML + ' ]', 'string', constants.DEFAULT_OPTIONS.target ], + indent: [ 'i', 'The indention for pretty-print: 1 - 8', 'int', constants.DEFAULT_INDENT ], + force: [ 'f', 'Force overwriting of existing output files on write phase: when files are not overwritten (which is default), then the next transformation with same output file name gets a consecutive number on the base file name, e.g. in case of foo.yaml it would be foo(1).yaml' ], + imports: [ 'm', 'Define a \'module.exports[.identifier] = \' identifier (to read from JS _source_ file only, must be a valid JS identifier!)', 'string', constants.DEFAULT_OPTIONS.imports ], + exports: [ 'x', 'Define a \'module.exports[.identifier] = \' identifier (for usage in JS destination file only, must be a valid JS identifier!)', 'string', constants.DEFAULT_OPTIONS.exports ] }; /** - * The main entry callback. When calling cli.main() this receives the `options` - * given on CLI, does the transformation with these options and prints the - * result to the CLI. + * Prints the error to console and exit with 1. * - * @param args - Not used inside this method! - * @param options - The options set on CLI. + * @param {string|Error} err - The error to print. + * @private + */ +function error(err) { + cli.error('////////////////////////////////////////////////////////////////////////////////'); + cli.error(err); + if (err.stack) { + cli.debug(err.stack); + } + cli.error('////////////////////////////////////////////////////////////////////////////////'); + cli.getUsage(1); +} + +/** + * The main entry callback. When calling `cli.main()` this receives the `options` + * given on CLI, then does the transformation with these options and finally, it + * prints the result to the CLI. + * + * @param {array} args - The first mandatory argument is the input file + * (`args[0]`), the second (optional) argument is the + * output file (`args[0]`). + * @param {object} options - The options set on CLI. * @private */ function main(args, options) { + + // read file args and set to options + + if (args.length > 0) { + cli.debug('input file: ' + args[0]); + options.src = args[0]; + } else { + error('please specify an input file as first argument!'); + } + if (args.length > 1) { + cli.debug('output file: ' + args[1]); + options.dest = args[1]; + } else { + cli.debug('output file not specified, using default'); + } + + // transform with options + return transformer.transform(options) .then(function (msg) { cli.info(msg); }) .catch(function (err) { - cli.error('////////////////////////////////////////////////////////////////////////////////'); - cli.error(err); - cli.debug(err.stack); - cli.error('////////////////////////////////////////////////////////////////////////////////'); - cli.getUsage(1); + error(err); }); } /** * Init the CLI instance. */ +cli.width = 120; cli.setUsage(usage); cli.setApp(packagePath); cli.enable('version', 'status', 'timeout'); diff --git a/lib/constants.js b/lib/constants.js index e76b16b..fab466e 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -100,6 +100,7 @@ Constants.prototype.MAX_INDENT = 8; * The default `origin` value: 'yaml'. * * @type {string} + * @constant * @public */ Constants.prototype.DEFAULT_ORIGIN = constants.YAML; @@ -108,6 +109,7 @@ Constants.prototype.DEFAULT_ORIGIN = constants.YAML; * The default `origin` value: 'js'. * * @type {string} + * @constant * @public */ Constants.prototype.DEFAULT_TARGET = constants.JS; @@ -116,6 +118,7 @@ Constants.prototype.DEFAULT_TARGET = constants.JS; * Whether to overwrite existing file or object on output. * * @type {boolean} + * @constant * @public */ Constants.prototype.DEFAULT_FORCE_FILE_OVERWRITE = false; @@ -124,22 +127,25 @@ Constants.prototype.DEFAULT_FORCE_FILE_OVERWRITE = false; * The `origin` description value. * * @type {string} + * @constant * @public */ -Constants.prototype.ORIGIN_DESCRIPTION = ': if not given, the type is tried to be inferred from the extension of source path, else it is \'' + constants.DEFAULT_ORIGIN + '\''; +Constants.prototype.ORIGIN_DESCRIPTION = 'if not given, the type is tried to be inferred from the extension of source path, else it is \'' + constants.DEFAULT_ORIGIN + '\''; /** * The `target` description value. * * @type {string} + * @constant * @public */ -Constants.prototype.TARGET_DESCRIPTION = ': if not given, the type is tried to be inferred from the extension of destination path, else it is \'' + constants.DEFAULT_TARGET + '\''; +Constants.prototype.TARGET_DESCRIPTION = 'if not given, the type is tried to be inferred from the extension of destination path, else it is \'' + constants.DEFAULT_TARGET + '\''; /** * The `dest` description value. * * @type {string} + * @constant * @public */ Constants.prototype.DEST_DESCRIPTION = 'storing relative to input file'; @@ -149,6 +155,7 @@ Constants.prototype.DEST_DESCRIPTION = 'storing relative to input file'; * * @type {string} * @public + * @constant * @example * module.exports.foo = {...}; // here 'foo' is the identifier for an object to read from the source! */ @@ -159,6 +166,7 @@ Constants.prototype.DEFAULT_JS_IMPORTS_IDENTIFIER = undefined; * * @type {string} * @public + * @constant */ Constants.prototype.DEFAULT_JS_EXPORTS_IDENTIFIER = undefined; @@ -174,9 +182,9 @@ Constants.prototype.DEFAULT_JS_EXPORTS_IDENTIFIER = undefined; * @property {boolean} force=false - Whether to overwrite existing file on output. * @property {string} imports=undefined - The exports name for reading from JS source file or objects only. * @property {string} exports=undefined - The exports name for usage in JS file or object only. - * @see {@link Constants#ORIGIN_DESCRIPTION} - * @see {@link Constants#TARGET_DESCRIPTION} - * @see {@link Constants#DEST_DESCRIPTION} + * @see {@link ORIGIN_DESCRIPTION} + * @see {@link TARGET_DESCRIPTION} + * @see {@link DEST_DESCRIPTION} */ Constants.prototype.DEFAULT_OPTIONS = { origin: constants.ORIGIN_DESCRIPTION, @@ -189,7 +197,7 @@ Constants.prototype.DEFAULT_OPTIONS = { }; /** - * The transformation direction YAML => JS. + * The transformation direction YAML ⇒ JS. * * @type {string} * @constant @@ -198,7 +206,7 @@ Constants.prototype.DEFAULT_OPTIONS = { Constants.prototype.YAML_TO_JS = 'yaml2js'; /** - * The transformation direction YAML => JSON. + * The transformation direction YAML ⇒ JSON. * * @type {string} * @constant @@ -207,7 +215,7 @@ Constants.prototype.YAML_TO_JS = 'yaml2js'; Constants.prototype.YAML_TO_JSON = 'yaml2json'; /** - * The transformation direction JS => YAML. + * The transformation direction JS ⇒ YAML. * * @type {string} * @constant @@ -216,7 +224,7 @@ Constants.prototype.YAML_TO_JSON = 'yaml2json'; Constants.prototype.JS_TO_YAML = 'js2yaml'; /** - * The transformation direction JSON => YAML. + * The transformation direction JSON ⇒ YAML. * * @type {string} * @constant @@ -225,7 +233,7 @@ Constants.prototype.JS_TO_YAML = 'js2yaml'; Constants.prototype.JSON_TO_YAML = 'json2yaml'; /** - * The transformation direction JSON => JS. + * The transformation direction JSON ⇒ JS. * * @type {string} * @constant @@ -234,7 +242,7 @@ Constants.prototype.JSON_TO_YAML = 'json2yaml'; Constants.prototype.JSON_TO_JS = 'json2js'; /** - * The transformation direction JS => JSON. + * The transformation direction JS ⇒ JSON. * * @type {string} * @constant @@ -243,7 +251,7 @@ Constants.prototype.JSON_TO_JS = 'json2js'; Constants.prototype.JS_TO_JSON = 'js2json'; /** - * The transformation direction YAML => YAML. + * The transformation direction YAML ⇒ YAML. * * @type {string} * @constant @@ -252,7 +260,7 @@ Constants.prototype.JS_TO_JSON = 'js2json'; Constants.prototype.YAML_TO_YAML = 'yaml2yaml'; /** - * The transformation direction JSON => JSON. + * The transformation direction JSON ⇒ JSON. * * @type {string} * @constant @@ -261,7 +269,7 @@ Constants.prototype.YAML_TO_YAML = 'yaml2yaml'; Constants.prototype.JSON_TO_JSON = 'json2json'; /** - * The transformation direction JS => JS. + * The transformation direction JS ⇒ JS. * * @type {string} * @constant diff --git a/lib/log-wrapper.js b/lib/log-wrapper.js index 2f68987..2bbb053 100644 --- a/lib/log-wrapper.js +++ b/lib/log-wrapper.js @@ -39,7 +39,22 @@ LogWrapper.prototype.constructor = LogWrapper; /////////////////////////////////////////////////////////////////////////////// /** - * Log the options with DEBUG level (logger supports it, else with INFO). + * Log the options with INFO level. + * + * @param {string} msg - The message to log. + * @example + * var logger = ...; + * var logWrapper = new LogWrapper(logger); + * var msg = '...'; + * logWrapper.info(msg); + * @public + */ +LogWrapper.prototype.info = function (msg) { + this.logInstance.info(msg); +}; + +/** + * Log the options with DEBUG level (if logger supports it, else with INFO). * * @param {string} msg - The message to log. * @example @@ -58,18 +73,23 @@ LogWrapper.prototype.debug = function (msg) { }; /** - * Log the options with INFO level. + * Log the options with TRACE level (if logger supports it, else with DEBUG). * * @param {string} msg - The message to log. * @example * var logger = ...; * var logWrapper = new LogWrapper(logger); * var msg = '...'; - * logWrapper.info(msg); + * logWrapper.trace(msg); * @public + * @see {@link #debug} */ -LogWrapper.prototype.info = function (msg) { - this.logInstance.info(msg); +LogWrapper.prototype.trace = function (msg) { + if (this.logInstance.trace && typeof this.logInstance.trace === 'function') { + this.logInstance.trace(msg); + } else { + this.debug(msg); + } }; /** diff --git a/lib/options-handler.js b/lib/options-handler.js index b550579..0dd221c 100644 --- a/lib/options-handler.js +++ b/lib/options-handler.js @@ -1,7 +1,7 @@ 'use strict'; -var Constants = require('./constants.js'); -var LogWrapper = require('./log-wrapper.js'); +var Constants = require('./constants'); +var LogWrapper = require('./log-wrapper'); var Promise = require('bluebird'); var path = require('path'); var fs = require('fs'); @@ -9,13 +9,13 @@ var isStream = require('is-stream'); /** * @typedef {object} Options - * @property {string} [origin=yaml] - The origin type. - * @property {string} [target=js] - The target type. - * @property {(string|Readable|object)} src - The source. - * @property {(string|Writable|object)} [dest] - The destination. - * @property {number} [indent=4] - The indention in files. - * @property {string} [imports=undefined] - The exports name for reading from JS source file or objects only. - * @property {string} [exports=undefined] - The exports name for usage in JS destination files only. + * @property {string} [origin=yaml] - The origin type. + * @property {string} [target=js] - The target type. + * @property {(string|Readable|object)} src - The source (`string` type is treated as a file path). + * @property {(string|Writable|object)} [dest] - The destination (`string` type is treated as a file path). + * @property {number} [indent=4] - The indention in files. + * @property {string} [imports=undefined] - The exports name for reading from JS source file or objects only. + * @property {string} [exports=undefined] - The exports name for usage in JS destination files only. */ /////////////////////////////////////////////////////////////////////////////// @@ -34,7 +34,7 @@ var isStream = require('is-stream'); * **NOTE:** This class is not to be intended to be called from * outside this module! * @example - * var OptionsHandler = require('./options-handler.js'); + * var OptionsHandler = require('./options-handler'); * var logger = ...; * * var optionsHandler = new OptionsHandler(logger); @@ -124,7 +124,7 @@ function OptionsHandler(logger) { * * @param {string} pathStr - The file path with or without extension. * @param {boolean} origin - If the type is origin (true) or target (false) - * @param {string} defaultValue - The default value to use if it cannot inferred from path. + * @param {string} defaultValue - The default value to use if type cannot be inferred from path. * @returns {string} - A type value. * @private */ @@ -172,13 +172,17 @@ function OptionsHandler(logger) { .then(function (assertedOptions) { var srcType; var destType; - if (assertedOptions.src && (typeof assertedOptions.src === 'string')) { - srcType = getTypeFromFilePath(assertedOptions.src, true, Constants.YAML); + if (assertedOptions.src) { + if (typeof assertedOptions.src === 'string') { + srcType = getTypeFromFilePath(assertedOptions.src, true, Constants.YAML); + } else if (typeof assertedOptions.src === 'object') { + srcType = Constants.JS; + } // TODO: what about stream? } self.logInstance.debug('srcType: ' + srcType); if (assertedOptions.dest && (typeof assertedOptions.dest === 'string')) { self.logInstance.debug('options.dest: ' + assertedOptions.dest); - destType = getTypeFromFilePath(assertedOptions.dest, false, Constants.JS); + destType = getTypeFromFilePath(assertedOptions.dest, false, Constants.JS); // TODO: what about stream? } self.logInstance.debug('destType: ' + destType); @@ -212,32 +216,88 @@ function OptionsHandler(logger) { * @public */ this.ensureSrc = function (options) { + //return assertOptions(options, ['src']) + // .then(function (assertedOptions) { + // if (typeof assertedOptions.src === 'string') { + // self.logInstance.debug('options.src is to be verfied as File path: ' + assertedOptions.src); + // // check for existing source file + // try { + // var stats = fs.statSync(assertedOptions.src); + // if (stats.isDirectory()) { + // return Promise.reject(new Error('Source file (options.src) is a directory, pls specify a valid file resource!')); + // } + // } catch (err) { + // err.message = 'Error occurred while checking input file \'' + assertedOptions.src + '\' which should be existing and accessible, code: ' + err.code + ', cause: ' + err.message; + // return Promise.reject(err); + // } + // } else if (isStream.readable(assertedOptions.src)) { + // self.logInstance.debug('options.src is Readable stream'); + // if (!options.origin) { + // return Promise.reject(new Error('When options.src is a Readable stream then setting options.origin is mandatory!')); + // } + // } else { + // self.logInstance.debug('options.src is JSON Object'); + // } + // return assertedOptions; + //}); + return assertOptions(options, ['src']) - .then(function (assertedOptions) { - if (typeof assertedOptions.src === 'string') { - self.logInstance.debug('options.src is to be verfied as File path: ' + assertedOptions.src); - // check for existing source file - try { - var stats = fs.statSync(assertedOptions.src); - if (stats.isDirectory()) { - return Promise.reject(new Error('Source file (options.src) is a directory, pls specify a valid file resource!')); - } - } catch (err) { - err.message = 'Error occurred while checking input file \'' + assertedOptions.src + '\' which should be existing and accessible, code: ' + err.code + ', cause: ' + err.message; - return Promise.reject(err); - } - } else if (isStream.readable(assertedOptions.src)) { - self.logInstance.debug('options.src is Readable stream'); - if (!options.origin) { - return Promise.reject(new Error('When options.src is a Readable stream then setting options.origin is mandatory!')); - } - } else { + .then(function (options) { + return assertFileSrc(options); + }) + .spread(function (checked, options) { + if (!checked) { + return assertStreamSrc(options); + } + return [checked, options]; + }) + .spread(function (checked, options) { + if (!checked) { self.logInstance.debug('options.src is JSON Object'); } - return assertedOptions; - }); + return Promise.resolve(options); + }) + .catch(function (err) { + self.logInstance.error('options.src is unknown or invalid object: ' + options.src); + return Promise.reject(err); + }); }; + function assertFileSrc(options) { + return new Promise(function (resolve, reject) { + if (typeof options.src === 'string') { + self.logInstance.debug('options.src is to be verified as File path: ' + options.src); + // check for existing source file + try { + var stats = fs.statSync(options.src); + if (stats.isDirectory()) { + return reject(new Error('Source file (options.src) is a directory, pls specify a valid file resource!')); + } + return resolve([true, options]); + } catch (err) { + err.message = 'Error occurred while checking input file \'' + options.src + '\' which should be existing and accessible, code: ' + err.code + ', cause: ' + err.message; + return reject(err); + } + } else { + return resolve([false, options]); + } + }); + } + + function assertStreamSrc(options) { + return new Promise(function (resolve, reject) { + if (isStream.readable(options.src)) { + self.logInstance.debug('options.src is Readable stream'); + if (!options.origin) { + return reject(new Error('when options.src is a Readable stream, then setting options.origin is mandatory!')); + } + return resolve([true, options]); + } else { + return resolve([false, options]); + } + }); + } + /** * This method ensures that destination file path is created if not set in * options. If not, then it creates the path relative to the source file using @@ -347,7 +407,7 @@ function OptionsHandler(logger) { this.ensureIndent = function (options) { return assertOptions(options) .then(function (assertedOptions) { - self.logInstance.debug('options before ensureIndent():: ' + JSON.stringify(assertedOptions, null, 4)); + self.logInstance.trace('options before ensureIndent():: ' + JSON.stringify(assertedOptions, null, 4)); if (assertedOptions.indent === undefined) { self.logInstance.info('Missing indention, reset to default: ' + Constants.DEFAULT_INDENT); assertedOptions.indent = Constants.DEFAULT_INDENT; @@ -358,7 +418,7 @@ function OptionsHandler(logger) { self.logInstance.info('Indention \'' + assertedOptions.indent + '\' is too wide, reset to default: ' + Constants.DEFAULT_INDENT); assertedOptions.indent = Constants.DEFAULT_INDENT; } - self.logInstance.debug('options after ensureIndent():: ' + JSON.stringify(assertedOptions, null, 4)); + self.logInstance.trace('options after ensureIndent():: ' + JSON.stringify(assertedOptions, null, 4)); return assertedOptions; }); }; diff --git a/lib/reader.js b/lib/reader.js index 07beccd..1c64e2d 100644 --- a/lib/reader.js +++ b/lib/reader.js @@ -1,9 +1,9 @@ 'use strict'; -var Constants = require('./constants.js'); -var LogWrapper = require('./log-wrapper.js'); -var OptionsHandler = require('./options-handler.js'); -var Validator = require('./validator.js'); +var Constants = require('./constants'); +var LogWrapper = require('./log-wrapper'); +var OptionsHandler = require('./options-handler'); +var Validator = require('./validator'); var jsYaml = require('js-yaml'); var Promise = require('bluebird'); var fs = Promise.promisifyAll(require('fs')); @@ -68,7 +68,7 @@ function Reader(logger) { return function () { var chunk; while (null !== (chunk = readable.read())) { - self.logInstance.debug('JSON chunk: ', chunk); + self.logInstance.trace('JSON chunk: ', chunk); bufs.push(chunk); } }; @@ -80,7 +80,7 @@ function Reader(logger) { * @param {stream.Readable} readable - The source to read from. * @param {function} resolve - Callback for success case. * @param {function} reject - Callback for Error case. - * @param {string} origin - Origin type, must be 'yaml' or 'json'. + * @param {string} origin - Origin type, must be 'yaml' or 'json'/'js'. * @private */ function readFromStream(readable, resolve, reject, origin) { @@ -93,12 +93,16 @@ function Reader(logger) { .on('end', function () { var buffer = Buffer.concat(bufs); try { - if (origin === Constants.JSON) { + self.logInstance.debug(origin + ' reading from Readable'); + if (origin === Constants.JSON || origin === Constants.JS) { resolve(JSON.parse(buffer.toString(Constants.UTF8))); - } else if (origin === Constants.YAML) { + } else {// HINT: commented (see below): if (origin === Constants.YAML) { resolve(jsYaml.safeLoad(buffer.toString(Constants.UTF8))); } - self.logInstance.debug(origin + ' loaded from stream'); + // HINT: for the sake of test coverage it's commented, since this is a private method we have control over options.origin inside this class! + //else { + // reject(new Error('Unsupported type: ' + origin + ' to read from Readable')); + //} } catch (err) { // probably a SyntaxError for JSON or a YAMLException self.logInstance.error('Unexpected error: ' + err.stack); readable.emit('error', err); // send to .on('error',... @@ -111,7 +115,7 @@ function Reader(logger) { /////////////////////////////////////////////////////////////////////////////// /** - * Reads the data from a given JS or JSON source. + * Reads the data from a given JS or JSON source. * * @param {Options} options - Contains the JS/JSON source reference to read from. * @returns {Promise} - Contains the read JS object. @@ -119,10 +123,14 @@ function Reader(logger) { * @example * var Reader = require('jy-transform').Reader; * var logger = ...; + * var reader = new Reader(logger); + * + * // --- from file path + * * var options = { * src: 'foo.js' * }; - * var reader = new Reader(logger); + * * reader.readJs(options) * .then(function (obj){ * logger.info(JSON.stringify(obj)); @@ -131,9 +139,13 @@ function Reader(logger) { * logger.error(err.stack); * }); * + * + * // --- from Readable + * * options = { * src: fs.createReadStream('foo.js') * }; + * * reader.readJs(options) * .then(function (obj){ * logger.info(JSON.stringify(obj)); @@ -142,11 +154,15 @@ function Reader(logger) { * logger.error(err.stack); * }); * + * + * // --- from object + * * options = { * src: { * foo: 'bar' * } * }; + * * reader.readJs(options) * .then(function (obj){ * logger.info(JSON.stringify(obj)); @@ -156,7 +172,7 @@ function Reader(logger) { * }); */ this.readJs = function (options) { - self.logInstance.debug('OPTIONS BEFORE ASSERTING IN readJs:::' + JSON.stringify(options)); + self.logInstance.trace('OPTIONS BEFORE ASSERTING IN readJs:::' + JSON.stringify(options)); return self.optionsHandler.assertOptions(options, ['src']) .then(function (assertedOptions) { return new Promise(function (resolve, reject) { @@ -170,7 +186,7 @@ function Reader(logger) { reject(new Error('found invalid identifier for reading from exports: ' + stringify(options.imports, null, 4))); } else { var json = require(resolvedPath)[options.imports]; - self.logInstance.debug('LOADED JSON object (' + options.imports + '):: ' + stringify(json, null, 4)); + self.logInstance.trace('LOADED JSON object (' + options.imports + '):: ' + stringify(json, null, 4)); if (!json) { reject(new Error('an identifier string \'' + options.imports + '\' was specified for JS object but could not find this object, pls ensure that file ' + assertedOptions.src + ' contains it.')); } else { @@ -193,7 +209,7 @@ function Reader(logger) { reject(new Error('found invalid identifier for reading from object: ' + stringify(options.imports, null, 4))); } else { var obj = assertedOptions.src[options.imports]; - self.logInstance.debug('LOADED JSON object (' + options.imports + '):: ' + stringify(obj, null, 4)); + self.logInstance.trace('LOADED JSON object (' + options.imports + '):: ' + stringify(obj, null, 4)); if (!obj) { reject(new Error('an identifier string \'' + options.imports + '\' was specified for JS object but could not find this object, pls ensure that object source contains it.')); } else { @@ -219,9 +235,15 @@ function Reader(logger) { * @example * var Reader = require('jy-transform').Reader; * var logger = ...; - * * var reader = new Reader(logger); - * reader.readYaml('foo.yaml') + * + * // --- from file path + * + * options = { + * src: 'foo.yml' + * }; + * + * reader.readYaml(options) * .then(function (obj){ * logger.info(JSON.stringify(obj)); * }) @@ -229,9 +251,13 @@ function Reader(logger) { * logger.error(err.stack); * }); * + * + * // --- from Readable + * * options = { * src: fs.createReadStream('foo.yml') * }; + * * reader.readJs(options) * .then(function (obj){ * logger.info(JSON.stringify(obj)); @@ -241,7 +267,7 @@ function Reader(logger) { * }); */ this.readYaml = function (options) { - self.logInstance.debug('OPTIONS BEFORE ASSERTING IN readYaml::: ' + JSON.stringify(options)); + self.logInstance.trace('OPTIONS BEFORE ASSERTING IN readYaml::: ' + JSON.stringify(options)); return self.optionsHandler.assertOptions(options, ['src']) .then(function (assertedOptions) { return new Promise(function (resolve, reject) { @@ -258,7 +284,6 @@ function Reader(logger) { } }); } else if (isStream.readable(assertedOptions.src)) { - // read YAML readFromStream(assertedOptions.src, resolve, reject, Constants.YAML); } else { resolve(assertedOptions.src); @@ -284,7 +309,7 @@ function Reader(logger) { // return Promise.resolve().then(function () { // var jsDocs = []; // return jsYaml.safeLoadAll(yaml, function (doc) { // TOD this will not work in Promise environment!!! -// self.logger.debug(doc); +// self.logger.trace(doc); // jsDocs.push(doc); // }); // }); diff --git a/lib/transformer.js b/lib/transformer.js index 3ecdea1..e1e5790 100644 --- a/lib/transformer.js +++ b/lib/transformer.js @@ -1,10 +1,10 @@ 'use strict'; -var Writer = require('./writer.js'); -var Reader = require('./reader.js'); -var LogWrapper = require('./log-wrapper.js'); -var OptionsHandler = require('./options-handler.js'); -var middleware = require('./middleware.js'); +var Writer = require('./writer'); +var Reader = require('./reader'); +var LogWrapper = require('./log-wrapper'); +var OptionsHandler = require('./options-handler'); +var middleware = require('./middleware'); var path = require('path'); /////////////////////////////////////////////////////////////////////////////// diff --git a/lib/validator.js b/lib/validator.js index c5ad71f..e1064f7 100644 --- a/lib/validator.js +++ b/lib/validator.js @@ -1,8 +1,8 @@ 'use strict'; -var Constants = require('./constants.js'); -var LogWrapper = require('./log-wrapper.js'); -var OptionsHandler = require('./options-handler.js'); +var Constants = require('./constants'); +var LogWrapper = require('./log-wrapper'); +var OptionsHandler = require('./options-handler'); var Promise = require('bluebird'); var stringify = require('json-stringify-safe'); var path = require('path'); diff --git a/lib/writer.js b/lib/writer.js index 320c6f9..0326e34 100644 --- a/lib/writer.js +++ b/lib/writer.js @@ -1,9 +1,9 @@ 'use strict'; -var Constants = require('./constants.js'); -var LogWrapper = require('./log-wrapper.js'); -var OptionsHandler = require('./options-handler.js'); -var Validator = require('./validator.js'); +var Constants = require('./constants'); +var LogWrapper = require('./log-wrapper'); +var OptionsHandler = require('./options-handler'); +var Validator = require('./validator'); var serializeJs = require('serialize-js'); var jsYaml = require('js-yaml'); var Promise = require('bluebird'); @@ -26,7 +26,7 @@ var isStream = require('is-stream'); * @constructor * @class This class provides utility methods usable to write JS objects * from memory to a JSON/JS/YAML destination - * (file, {object} or {@link stream.Readable}). + * (file, object or {@link stream.Readable}). * @example * var Writer = require('jy-transform').Writer; * var logger = ...; @@ -34,6 +34,7 @@ var isStream = require('is-stream'); * var writer = new Writer(logger); */ function Writer(logger) { + /** * The logger instance. * @@ -95,6 +96,7 @@ function Writer(logger) { * @param {string} [exportsTo] - Name for export (*IMPORTANT:* must be a valid ES6 identifier). * @returns {Promise} - Promise resolve with the serialized JS object. * @private + * @todo [[#35](https://github.com/deadratfink/jy-transform/issues/35)] Add `'use strict';` in JS output file (-> `'\'use strict\';' + os.EOL + os.EOL + ...`)? */ function serializeJsToString(object, indent, exportsTo) { return createExportsString(exportsTo) @@ -244,6 +246,8 @@ function Writer(logger) { * var logger = ...; * var writer = new Writer(logger); * + * // ---- write obj to file + * * var obj = {...}, * var options = { * dest: 'result.yml', @@ -258,6 +262,9 @@ function Writer(logger) { * logger.error(err.stack); * }); * + * + * // ---- write obj to Writable + * * options = { * dest: fs.createWriteStream('result.yml'), * indent: 4 @@ -294,7 +301,7 @@ function Writer(logger) { writeToFile(yaml, dest, Constants.YAML, resolve, reject, ensuredOptions.force); } else if (isStream.writable(dest)) { // stream writeToStream(yaml, dest, Constants.YAML, resolve, reject); - } else { // file + } else { // object ensuredOptions.dest = yaml; resolve('Writing YAML to options.dest successful.'); } @@ -318,6 +325,8 @@ function Writer(logger) { * var logger = ...; * var writer = new Writer(logger); * + * // ---- write obj to file + * * var obj = {...}; * var options = { * dest: 'result.json', @@ -332,6 +341,9 @@ function Writer(logger) { * logger.error(err.stack); * }); * + * + * // ---- write obj to Writable + * * options = { * dest: fs.createWriteStream('result.json'), * indent: 4 @@ -345,6 +357,8 @@ function Writer(logger) { * logger.error(err.stack); * }); * + * // ---- write obj to object + * * options = { * dest: {}, * indent: 4 @@ -396,6 +410,8 @@ function Writer(logger) { * var logger = ...; * var writer = new Writer(logger); * + * // ---- write obj to file + * * var obj = {...}; * var options = { * dest: 'result.js', @@ -410,6 +426,9 @@ function Writer(logger) { * logger.error(err.stack); * }); * + * + * // ---- write obj to Writable + * * options = { * dest: fs.createWriteStream('result.json'), * indent: 4 @@ -423,6 +442,9 @@ function Writer(logger) { * logger.error(err.stack); * }); * + * + * // ---- write obj to object + * * options = { * dest: {}, * indent: 2 diff --git a/package.json b/package.json index 1b86989..2fcf0a0 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "jy-transform", - "description": "This project aims to read, write and transform YAML, JS or JSON objects into each other using CLI or API. The source and destination resources can be files on CLI and additionally, objects or streams on API level. Besides the transformation feature this module can also be used for simple loading and/or writing YAML, JS or JSON files.", - "version": "1.0.2", + "description": "This project aims to read, write and transform YAML, JS or JSON objects into each other using CLI or API, while the source and destination resources can be files on CLI and additionally, objects or streams on API level.", + "version": "2.0.0", "homepage": "https://github.com/deadratfink/jy-transform", "author": { "name": "Jens Krefeldt", @@ -9,11 +9,6 @@ "url": "https://github.com/deadratfink" }, "contributors": [ - { - "name": "Jens Krefeldt", - "email": "j.krefeldt@gmail.com", - "url": "https://github.com/deadratfink" - } ], "license": "SEE LICENSE IN [LICENSE.md](https://github.com/deadratfink/jy-transform/blob/master/LICENSE.md)", "repository": { @@ -35,35 +30,35 @@ } }, "scripts": { - "docs": "cat docs/BADGES.md > README.md && cat docs/TOC.md >> README.md && package-json-to-readme --no-footer ./package.json >> README.md && cat docs/USAGE.md >> README.md && echo '\n\n' >> README.md && cat docs/CONTRIBUTING.md >> README.md && doctoc README.md --github --title '# TOC' --maxlevel 2", - "wiki": "jsdoc2md lib/*.js index.js > docs/API.md && doctoc docs/API.md --github --title '### TOC' --maxlevel 2 && cat docs/API.md > '../jy-transform.wiki/API-v1.0.md' && cat CHANGELOG.md > ../jy-transform.wiki/Changelog.md && doctoc ../jy-transform.wiki/Changelog.md --github --title '### TOC' --maxlevel 3", + "docs": "cat docs/LOGO.md > README.md && cat docs/BADGES.md >> README.md && cat docs/TOC.md >> README.md && package-json-to-readme --no-footer ./package.json >> README.md && cat docs/USAGE.md >> README.md && echo '\n\n' >> README.md && cat docs/CHANGELOG.md >> README.md && doctoc README.md --github --title '# TOC' --maxlevel 2", + "wiki": "jsdoc2md ./jyt lib/*.js index.js > docs/API.md && doctoc docs/API.md --github --title '### TOC' --maxlevel 2 && cat docs/API.md > '../jy-transform.wiki/API-v2.md' && cat docs/CONTRIBUTING.md > ../jy-transform.wiki/Contributing.md && cat docs/CHANGELOG.md > ../jy-transform.wiki/Changelog.md && doctoc ../jy-transform.wiki/Changelog.md --github --title '# TOC' --maxlevel 3", "test": "istanbul cover _mocha --report lcovonly -- -R $npm_package_config_test_mocha_unit_reporter ./test/test*.js" }, "engines": { "node": ">=0.10.0" }, "dependencies": { - "bluebird": "^3.3.3", - "cli": "^0.11.1", - "is-stream": "^1.0.1", - "js-yaml": "^3.4.2", + "bluebird": "^3.4.1", + "cli": "^0.11.2", + "is-stream": "^1.1.0", + "js-yaml": "^3.6.1", "json-stringify-safe": "^5.0.1", "mkdirp-then": "^1.2.0", "serialize-js": "^1.1.0" }, "devDependencies": { - "codeclimate-test-reporter": "^0.3.1", + "codeclimate-test-reporter": "^0.3.3", "codecov": "^1.0.1", - "coveralls": "^2.11.9", + "coveralls": "^2.11.11", "doctoc": "^1.0.0", - "fs-extra": "^0.26.7", - "istanbul": "^0.4.2", + "fs-extra": "^0.30.0", + "istanbul": "^0.4.4", "jsdoc-parse": "^1.2.7", - "jsdoc-to-markdown": "^1.3.3", - "mocha": "^2.3.3", + "jsdoc-to-markdown": "^1.3.6", + "mocha": "^2.5.3", "mocha-lcov-reporter": "^1.2.0", - "object-path": "^0.9.2", - "package-json-to-readme": "^1.5.0", + "object-path": "^0.11.1", + "package-json-to-readme": "^1.5.1", "winston": "^2.2.0" }, "preferGlobal": true, diff --git a/test/data/readable-test-dummy.txt b/test/data/readable-test-dummy.txt index 41fa1b9..1ae5c7d 100644 --- a/test/data/readable-test-dummy.txt +++ b/test/data/readable-test-dummy.txt @@ -1 +1,3 @@ -DO NOT DELETE THIS FILE, IT IS NEEDED FOR test-option-handler.js#ensureSrc() TEST! +{ + "important": "DO NOT DELETE THIS FILE, IT IS NEEDED FOR test-option-handler.js#ensureSrc() TEST!" +} diff --git a/test/test-log-wrapper.js b/test/test-log-wrapper.js index c64d502..0d91add 100644 --- a/test/test-log-wrapper.js +++ b/test/test-log-wrapper.js @@ -1,6 +1,6 @@ 'use strict'; -var LogWrapper = require('../lib/log-wrapper.js'); +var LogWrapper = require('../lib/log-wrapper'); var assert = require('assert'); /** @@ -10,12 +10,14 @@ describe('Executing \'jy-transform\' project log wrapper test suite.', function var infoMsg; var debugMsg; + var traceMsg; var errorMsg; var verboseResultArray = []; var logWrapper; var INFO = 'INFO'; var DEBUG = 'DEBUG'; + var TRACE = 'TRACE'; var ERROR = 'ERROR'; /** @@ -31,6 +33,9 @@ describe('Executing \'jy-transform\' project log wrapper test suite.', function debug: function (msg) { debugMsg = msg; }, + trace: function (msg) { + traceMsg = msg; + }, error: function (msg) { errorMsg = msg; } @@ -40,20 +45,32 @@ describe('Executing \'jy-transform\' project log wrapper test suite.', function info: function (msg) { infoMsg = msg; }, + trace: function (msg) { + traceMsg = msg; + }, error: function (msg) { errorMsg = msg; } }; - var mockLoggerWithVerboseFunction = { + var mockLoggerWithoutTraceFunction = { + info: function (msg) { + infoMsg = msg; + }, + debug: function (msg) { + debugMsg = msg; + }, + error: function (msg) { + errorMsg = msg; + } + }; + var mockLoggerWithVerboseFunction = { info: function (msg) { verboseResultArray.push(msg); } }; - - describe('Testing LogWrapper with mockLogger', function () { /** @@ -62,6 +79,7 @@ describe('Executing \'jy-transform\' project log wrapper test suite.', function beforeEach(function () { infoMsg = undefined; debugMsg = undefined; + traceMsg = undefined; errorMsg = undefined; logWrapper = new LogWrapper(mockLogger); }); @@ -80,6 +98,13 @@ describe('Executing \'jy-transform\' project log wrapper test suite.', function done(); }); + expected = TRACE; + it('should log with ' + expected, function (done) { + logWrapper.trace(expected); + assert.equal(traceMsg, expected, 'logger message should contain value ' + expected); + done(); + }); + expected = ERROR; it('should log with ' + expected, function (done) { logWrapper.error(expected); @@ -122,6 +147,7 @@ describe('Executing \'jy-transform\' project log wrapper test suite.', function beforeEach(function () { infoMsg = undefined; debugMsg = undefined; + traceMsg = undefined; errorMsg = undefined; logWrapper = new LogWrapper(mockLoggerWithoutDebugFunction); }); @@ -149,4 +175,39 @@ describe('Executing \'jy-transform\' project log wrapper test suite.', function }); + describe('Testing LogWrapper with mockLoggerWithoutTraceFunction', function () { + + /** + * Resets the mock logger message targets. + */ + beforeEach(function () { + infoMsg = undefined; + debugMsg = undefined; + errorMsg = undefined; + logWrapper = new LogWrapper(mockLoggerWithoutTraceFunction); + }); + + var expected = INFO; + it('should log with ' + expected, function (done) { + logWrapper.info(expected); + assert.equal(infoMsg, expected, 'logger message should contain value ' + expected); + done(); + }); + + expected = TRACE; + it('should log with ' + expected, function (done) { + logWrapper.trace(expected); + assert.equal(debugMsg, expected, 'logger message should contain value ' + expected); + done(); + }); + + expected = ERROR; + it('should log with ' + expected, function (done) { + logWrapper.error(expected); + assert.equal(errorMsg, expected, 'logger message should contain value ' + expected); + done(); + }); + + }); + }); diff --git a/test/test-middleware.js b/test/test-middleware.js index b8374c3..ee4c67b 100644 --- a/test/test-middleware.js +++ b/test/test-middleware.js @@ -1,7 +1,7 @@ 'use strict'; -var Transformer = require('../index.js'); -var Middleware = require('../index.js').middleware; +var Transformer = require('../index'); +var Middleware = require('../index').middleware; var identityMiddleware = Middleware.identityMiddleware; var transformer; var Promise = require('bluebird'); diff --git a/test/test-options-handler.js b/test/test-options-handler.js index b4aff4d..5aa67bf 100644 --- a/test/test-options-handler.js +++ b/test/test-options-handler.js @@ -1,11 +1,11 @@ 'use strict'; -var Constants = require('../lib/constants.js'); +var Constants = require('../lib/constants'); var assert = require('assert'); -var YAMLException = require('js-yaml/lib/js-yaml/exception.js'); +//var YAMLException = require('js-yaml/lib/js-yaml/exception'); var fs = require('fs'); var path = require('path'); -var OptionsHandler = require('../lib/options-handler.js'); +var OptionsHandler = require('../lib/options-handler'); var optionsHandler; var logger; @@ -103,7 +103,7 @@ describe('Executing \'jy-transform\' project OptionsHandler test suite.', functi assertOptionsError(null, optionsHandler.completeOptions, done); }); - it('should resolve options.src/orign and origin.dest/target with default values (' + Constants.DEFAULT_ORIGIN + '/' + Constants.DEFAULT_TARGET + ')', function (done) { + it('should resolve options.src/origin and options.dest/target with default values (' + Constants.DEFAULT_ORIGIN + '/' + Constants.DEFAULT_TARGET + ')', function (done) { var PATH_WITH_INVALID_EXT = 'PATH_WITH_INVALID.EXT'; var options = { src: PATH_WITH_INVALID_EXT, @@ -464,7 +464,7 @@ describe('Executing \'jy-transform\' project OptionsHandler test suite.', functi describe('Testing OptionsHandler.ensureSrc(...)', function () { it('should reject when options is missing', function (done) { - assertOptionsError(null, optionsHandler.ensureSrc, done); + assertOptionsError(null, optionsHandler.ensureSrc, done, TypeError); // TODO heck if this really TypeError!?! }); it('should reject when options.src is not given', function (done) { @@ -513,6 +513,24 @@ describe('Executing \'jy-transform\' project OptionsHandler test suite.', functi assertOptionsError(options, optionsHandler.ensureSrc, done); }); + it('should resolve original options.src Readable', function (done) { + var readable = fs.createReadStream('./test/data/readable-test-dummy.txt'); + var options = { + src: readable, + origin: Constants.JSON + }; + optionsHandler.ensureSrc(options) + .then(function (resultOptions) { + assert.notEqual(resultOptions.src, null, 'options should contain src but is missing'); + assert.equal(resultOptions.src, readable, 'result options.src should have type Readable'); + done(); + }) + .catch(function (err) { + logger.error('UNEXPECTED ERROR: ' + err.stack); + done(err); + }); + }); + it('should resolve original options.src object', function (done) { var srcObj = {}; var options = { diff --git a/test/test-reader.js b/test/test-reader.js index 19717e8..da4fe0c 100644 --- a/test/test-reader.js +++ b/test/test-reader.js @@ -1,10 +1,10 @@ 'use strict'; var assert = require('assert'); -var YAMLException = require('js-yaml/lib/js-yaml/exception.js'); +var YAMLException = require('js-yaml/lib/js-yaml/exception'); var fs = require('fs'); -var Reader = require('../index.js').Reader; -var Constants = require('../index.js').constants; +var Reader = require('../index').Reader; +var Constants = require('../index').constants; var logger; var reader; @@ -506,6 +506,5 @@ describe('Executing \'jy-transform\' project Reader test suite.', function () { done(); }); }); - }); }); diff --git a/test/test-transformer.js b/test/test-transformer.js index 5b6cbad..695e092 100644 --- a/test/test-transformer.js +++ b/test/test-transformer.js @@ -1,8 +1,8 @@ 'use strict'; -var Transformer = require('../index.js'); +var Transformer = require('../index'); var transformer; -var Constants = require('../lib/constants.js'); +var Constants = require('../lib/constants'); var logger; var jsYaml = require('js-yaml'); var assert = require('assert'); diff --git a/test/test-validator.js b/test/test-validator.js index c8a388b..d0a0725 100644 --- a/test/test-validator.js +++ b/test/test-validator.js @@ -6,7 +6,7 @@ var fs = require('fs'); var os = require('os'); var stringify = require('json-stringify-safe'); var stream = require('stream'); -var Validator = require('../lib/validator.js'); +var Validator = require('../lib/validator'); var logger; var validator; diff --git a/test/test-writer.js b/test/test-writer.js index 140eaa1..2b7a88c 100644 --- a/test/test-writer.js +++ b/test/test-writer.js @@ -2,11 +2,11 @@ var assert = require('assert'); var Promise = require('bluebird'); -var YAMLException = require('js-yaml/lib/js-yaml/exception.js'); +var YAMLException = require('js-yaml/lib/js-yaml/exception'); var fs = require('fs'); var os = require('os'); var stream = require('stream'); -var Writer = require('../index.js').Writer; +var Writer = require('../index').Writer; var logger; var writer; @@ -81,7 +81,6 @@ describe('Executing \'jy-transform\' project Writer test suite.', function () { test: 'value' }; - var errorThrowingStream = new stream.Writable(); errorThrowingStream._write = function (chunk, encoding, done) { logger.info('stream emitting Error now');