├── .gitignore ├── LICENSE.BSD ├── README.md ├── gulpfile.js ├── package.json ├── src └── index.js └── test ├── replace.js └── traverse.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | /lib/ 4 | /powered-test/ 5 | -------------------------------------------------------------------------------- /LICENSE.BSD: -------------------------------------------------------------------------------- 1 | Redistribution and use in source and binary forms, with or without 2 | modification, are permitted provided that the following conditions are met: 3 | 4 | * Redistributions of source code must retain the above copyright 5 | notice, this list of conditions and the following disclaimer. 6 | * Redistributions in binary form must reproduce the above copyright 7 | notice, this list of conditions and the following disclaimer in the 8 | documentation and/or other materials provided with the distribution. 9 | 10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 11 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 12 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 13 | ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 14 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 15 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 16 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 17 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 18 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 19 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Shift Traverse 2 | ============== 3 | 4 | 5 | ## About 6 | 7 | This module provides traversal functionality similar to [estraverse](https://github.com/estools/estraverse) for a [Shift format](https://github.com/shapesecurity/shift-spec) AST. 8 | 9 | 10 | 15 | 16 | ## Installation 17 | 18 | ```sh 19 | npm install shift-traverse 20 | ``` 21 | 22 | 23 | ## Usage 24 | 25 | ### traverse 26 | ```js 27 | // In ES6, but you can use it under ES5 environment. 28 | import {traverse} from "shift-traverse" 29 | 30 | traverse(tree, { 31 | enter(node) { 32 | console.log(`entering ${node.type}`); 33 | }, 34 | 35 | leave(node) { 36 | console.log(`leaving ${node.type}`); 37 | } 38 | }); 39 | ``` 40 | 41 | ### replace 42 | 43 | ```js 44 | import parse from 'shift-parser' 45 | import codegen from "shift-codegen"; 46 | import { LiteralStringExpression } from "shift-ast"; 47 | import { replace, Syntax } from '../' 48 | 49 | let code = ` 50 | function test() { 51 | console.log("HELLO WORLD"); 52 | } 53 | `; 54 | let tree = parse(code); 55 | let transformed = replace(tree, { 56 | enter(node, parent) { 57 | if (node.type === Syntax.LiteralStringExpression) { 58 | return new LiteralStringExpression('ご注文はうさぎですか?'); 59 | } 60 | } 61 | }); 62 | assert(codegen(transformed) === `function test(){console.log("ご注文はうさぎですか?")}`); 63 | ``` 64 | 65 | ### License 66 | 67 | Copyright (C) 2012-2014 [Yusuke Suzuki](http://github.com/Constellation) 68 | (twitter: [@Constellation](http://twitter.com/Constellation)) and other contributors. 69 | 70 | Redistribution and use in source and binary forms, with or without 71 | modification, are permitted provided that the following conditions are met: 72 | 73 | * Redistributions of source code must retain the above copyright 74 | notice, this list of conditions and the following disclaimer. 75 | 76 | * Redistributions in binary form must reproduce the above copyright 77 | notice, this list of conditions and the following disclaimer in the 78 | documentation and/or other materials provided with the distribution. 79 | 80 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 81 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 82 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 83 | ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 84 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 85 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 86 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 87 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 88 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 89 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 90 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014 Yusuke Suzuki 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' 14 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 17 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | */ 24 | 25 | 'use strict'; 26 | 27 | var gulp = require('gulp'), 28 | mocha = require('gulp-mocha'), 29 | to5 = require('gulp-6to5'), 30 | espower = require('gulp-espower'), 31 | git = require('gulp-git'), 32 | bump = require('gulp-bump'), 33 | filter = require('gulp-filter'), 34 | tagVersion = require('gulp-tag-version'), 35 | sourcemaps = require('gulp-sourcemaps'), 36 | plumber = require('gulp-plumber'), 37 | lazypipe = require('lazypipe'); 38 | 39 | var TEST = [ 'test/*.js' ]; 40 | var POWERED = [ 'powered-test/*.js' ]; 41 | var SOURCE = [ 'src/**/*.js' ]; 42 | 43 | var build = lazypipe() 44 | .pipe(sourcemaps.init) 45 | .pipe(to5) 46 | .pipe(sourcemaps.write) 47 | .pipe(gulp.dest, 'lib'); 48 | 49 | gulp.task('build-for-watch', function () { 50 | return gulp.src(SOURCE).pipe(plumber()).pipe(build()); 51 | }); 52 | 53 | gulp.task('build', function () { 54 | return gulp.src(SOURCE).pipe(build()); 55 | }); 56 | 57 | gulp.task('powered-test', function () { 58 | return gulp.src(TEST) 59 | .pipe(sourcemaps.init()) 60 | .pipe(to5()) 61 | .pipe(espower()) 62 | .pipe(sourcemaps.write()) 63 | .pipe(gulp.dest('./powered-test/')); 64 | }); 65 | 66 | gulp.task('test', [ 'build', 'powered-test' ], function () { 67 | return gulp.src(POWERED) 68 | .pipe(mocha({ 69 | reporter: 'spec', 70 | timeout: 100000 // 100s 71 | })); 72 | }); 73 | 74 | gulp.task('watch', [ 'build-for-watch' ], function () { 75 | gulp.watch(SOURCE, [ 'build-for-watch' ]); 76 | }); 77 | 78 | /** 79 | * Bumping version number and tagging the repository with it. 80 | * Please read http://semver.org/ 81 | * 82 | * You can use the commands 83 | * 84 | * gulp patch # makes v0.1.0 -> v0.1.1 85 | * gulp feature # makes v0.1.1 -> v0.2.0 86 | * gulp release # makes v0.2.1 -> v1.0.0 87 | * 88 | * To bump the version numbers accordingly after you did a patch, 89 | * introduced a feature or made a backwards-incompatible release. 90 | */ 91 | 92 | function inc(importance) { 93 | // get all the files to bump version in 94 | return gulp.src(['./package.json']) 95 | // bump the version number in those files 96 | .pipe(bump({type: importance})) 97 | // save it back to filesystem 98 | .pipe(gulp.dest('./')) 99 | // commit the changed version number 100 | .pipe(git.commit('Bumps package version')) 101 | // read only one file to get the version number 102 | .pipe(filter('package.json')) 103 | // **tag it in the repository** 104 | .pipe(tagVersion()); 105 | } 106 | 107 | gulp.task('patch', [ 'build' ], function () { return inc('patch'); }) 108 | gulp.task('minor', [ 'build' ], function () { return inc('minor'); }) 109 | gulp.task('major', [ 'build' ], function () { return inc('major'); }) 110 | 111 | gulp.task('travis', [ 'test' ]); 112 | gulp.task('default', [ 'travis' ]); 113 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shift-traverse", 3 | "version": "1.0.1", 4 | "description": "traversal functionality for the Shift AST format", 5 | "author": "Yusuke SUZUKI", 6 | "homepage": "https://github.com/Constellation/shift-traverse-js", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/Constellation/shift-traverse-js.git" 10 | }, 11 | "main": "lib/index.js", 12 | "maintainers": [ 13 | { 14 | "name": "Yusuke SUZUKI", 15 | "email": "utatane.tea@gmail.com", 16 | "web": "http://github.com/Constellation" 17 | } 18 | ], 19 | "files": [ 20 | "lib" 21 | ], 22 | "scripts": { 23 | "test": "gulp test" 24 | }, 25 | "dependencies": { 26 | "estraverse": "^1.9.1", 27 | "object-assign": "^2.0.0", 28 | "shift-spec": "^2015.1.3" 29 | }, 30 | "devDependencies": { 31 | "everything.js": "1.0.3", 32 | "gulp": "^3.8.10", 33 | "gulp-6to5": "^1.0.2", 34 | "gulp-bump": "^0.1.11", 35 | "gulp-espower": "^0.10.0", 36 | "gulp-filter": "^2.0.0", 37 | "gulp-git": "^0.5.5", 38 | "gulp-mocha": "^2.0.0", 39 | "gulp-plumber": "^0.6.6", 40 | "gulp-sourcemaps": "^1.3.0", 41 | "gulp-tag-version": "^1.2.1", 42 | "lazypipe": "^0.2.2", 43 | "power-assert": "^0.10.0", 44 | "shift-codegen": "^3.0.0", 45 | "shift-parser": "^3.0.1" 46 | }, 47 | "keywords": [ 48 | "Shift", 49 | "AST", 50 | "traversal", 51 | "abstract", 52 | "syntax", 53 | "tree" 54 | ], 55 | "bugs": { 56 | "url": "https://github.com/Constellation/shift-traverse-js/issues" 57 | }, 58 | "licenses": [ 59 | { 60 | "type": "BSD", 61 | "url": "http://github.com/Constellation/shift-traverse-js/raw/master/LICENSE.BSD" 62 | } 63 | ] 64 | } 65 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014 Yusuke Suzuki 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 17 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | */ 24 | 25 | import Spec from 'shift-spec' 26 | import * as objectAssign from 'object-assign' 27 | import { version } from '../package.json' 28 | 29 | // Loading uncached estraverse for changing estraverse.Syntax. 30 | const estraverse = require('estraverse').cloneEnvironment(); 31 | 32 | // Adjust estraverse members. 33 | 34 | Object.keys(estraverse.Syntax).filter(key => key !== 'Property').forEach((key) => { 35 | delete estraverse.Syntax[key]; 36 | delete estraverse.VisitorKeys[key]; 37 | }); 38 | 39 | objectAssign(estraverse.Syntax, Object.keys(Spec).reduce((result, key) => { 40 | result[key] = key; 41 | return result; 42 | }, {})); 43 | 44 | objectAssign(estraverse.VisitorKeys, Object.keys(Spec).reduce((result, key) => { 45 | result[key] = Spec[key].fields.map(field => field.name); 46 | return result; 47 | }, {})); 48 | 49 | estraverse.version = version; 50 | module.exports = estraverse; 51 | 52 | /* vim: set sw=4 ts=4 et tw=80 : */ 53 | -------------------------------------------------------------------------------- /test/replace.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014 Yusuke Suzuki 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 17 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | */ 24 | 25 | import * as assert from 'power-assert' 26 | import parse from 'shift-parser' 27 | import codegen from "shift-codegen"; 28 | import { replace, Syntax } from '../' 29 | 30 | describe('replace', () => { 31 | it('string literal', () => { 32 | let code = ` 33 | function test() { 34 | console.log("HELLO WORLD"); 35 | } 36 | `; 37 | let tree = parse(code); 38 | let transformed = replace(tree, { 39 | enter(node, parent) { 40 | if (node.type === Syntax.LiteralStringExpression) { 41 | return { 42 | type: 'LiteralStringExpression', 43 | value: 'ご注文はうさぎですか?' 44 | }; 45 | } 46 | } 47 | }); 48 | assert(codegen(transformed) === `function test(){console.log("ご注文はうさぎですか?")}`); 49 | }); 50 | }); 51 | 52 | 53 | /* vim: set sw=4 ts=4 et tw=80 : */ 54 | -------------------------------------------------------------------------------- /test/traverse.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014 Yusuke Suzuki 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 17 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | */ 24 | 25 | import * as fs from 'fs' 26 | import * as assert from 'power-assert' 27 | import { parseScript, parseModule } from 'shift-parser' 28 | import { traverse } from '../' 29 | 30 | describe('traverse', () => { 31 | it('enter', () => { 32 | let code = ` 33 | function test() { 34 | console.log("HELLO WORLD"); 35 | } 36 | `; 37 | let tree = parseScript(code); 38 | let result = []; 39 | traverse(tree, { 40 | enter(node) { 41 | result.push(node.type); 42 | } 43 | }); 44 | assert.deepEqual(result, [ 45 | 'Script', 46 | 'FunctionDeclaration', 47 | 'BindingIdentifier', 48 | 'FormalParameters', 49 | 'FunctionBody', 50 | 'ExpressionStatement', 51 | 'CallExpression', 52 | 'StaticMemberExpression', 53 | 'IdentifierExpression', 54 | 'LiteralStringExpression' 55 | ]); 56 | }); 57 | 58 | it('leave', () => { 59 | let code = ` 60 | function test() { 61 | console.log("HELLO WORLD"); 62 | } 63 | `; 64 | let tree = parseScript(code); 65 | let result = []; 66 | traverse(tree, { 67 | leave(node) { 68 | result.push(node.type); 69 | } 70 | }); 71 | assert.deepEqual(result, [ 72 | 'BindingIdentifier', 73 | 'FormalParameters', 74 | 'IdentifierExpression', 75 | 'StaticMemberExpression', 76 | 'LiteralStringExpression', 77 | 'CallExpression', 78 | 'ExpressionStatement', 79 | 'FunctionBody', 80 | 'FunctionDeclaration', 81 | 'Script' 82 | ]); 83 | }); 84 | 85 | it('both', () => { 86 | let code = ` 87 | function test() { 88 | console.log("HELLO WORLD"); 89 | } 90 | `; 91 | let tree = parseScript(code); 92 | let result = []; 93 | traverse(tree, { 94 | enter(node) { 95 | result.push(`enter:${node.type}`); 96 | }, 97 | 98 | leave(node) { 99 | result.push(`leave:${node.type}`); 100 | } 101 | }); 102 | assert.deepEqual(result, [ 103 | 'enter:Script', 104 | 'enter:FunctionDeclaration', 105 | 'enter:BindingIdentifier', 106 | 'leave:BindingIdentifier', 107 | 'enter:FormalParameters', 108 | 'leave:FormalParameters', 109 | 'enter:FunctionBody', 110 | 'enter:ExpressionStatement', 111 | 'enter:CallExpression', 112 | 'enter:StaticMemberExpression', 113 | 'enter:IdentifierExpression', 114 | 'leave:IdentifierExpression', 115 | 'leave:StaticMemberExpression', 116 | 'enter:LiteralStringExpression', 117 | 'leave:LiteralStringExpression', 118 | 'leave:CallExpression', 119 | 'leave:ExpressionStatement', 120 | 'leave:FunctionBody', 121 | 'leave:FunctionDeclaration', 122 | 'leave:Script' 123 | ]); 124 | }); 125 | 126 | it('should traverse es2015 modules', () => { 127 | let code = fs.readFileSync(require.resolve('everything.js/es2015-module')); 128 | let tree = parseModule(code.toString()); 129 | let result = []; 130 | 131 | traverse(tree, { 132 | enter(node) { 133 | result.push(node.type); 134 | } 135 | }); 136 | assert(result.length === 1772); 137 | }); 138 | 139 | it('should traverse es2015 scripts', () => { 140 | let code = fs.readFileSync(require.resolve('everything.js/es2015-script')); 141 | let tree = parseScript(code.toString()); 142 | let result = []; 143 | traverse(tree, { 144 | enter(node) { 145 | result.push(node.type); 146 | } 147 | }); 148 | assert(result.length === 1697); 149 | }); 150 | 151 | }); 152 | 153 | /* vim: set sw=4 ts=4 et tw=80 : */ 154 | --------------------------------------------------------------------------------