├── .eslintrc.json ├── test ├── sample-data │ ├── windows_crlf.gradle │ ├── windows_crlf.gradle.expected.js │ ├── small.build.gradle │ ├── test.compile.build.gradle │ ├── test.compile.build.gradle.expected.js │ ├── ivy.build.gradle │ ├── special.dependencies.build.gradle │ ├── ivy.build.gradle.expected.js │ ├── muzei.build.gradle │ └── muzei.build.gradle.expected.js └── parser.js ├── cli.js ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── package.json ├── README.md ├── .jscsrc ├── LICENSE ├── lib └── parser.js └── yarn.lock /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "google" 3 | } 4 | -------------------------------------------------------------------------------- /test/sample-data/windows_crlf.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.github.johnrengelman.shadow' version '2.0.3' 3 | id 'java' 4 | } 5 | version '0.0.1' 6 | sourceCompatibility = 1.8 7 | -------------------------------------------------------------------------------- /test/sample-data/windows_crlf.gradle.expected.js: -------------------------------------------------------------------------------- 1 | exports.expected = { 2 | plugins: [ 3 | { 4 | id: 'com.github.johnrengelman.shadow', 5 | version: '2.0.3' 6 | }, 7 | { 8 | id: 'java' 9 | } 10 | ], 11 | version: '0.0.1', 12 | sourceCompatibility: '1.8' 13 | } 14 | -------------------------------------------------------------------------------- /test/sample-data/small.build.gradle: -------------------------------------------------------------------------------- 1 | testblock { 2 | key1 "value1" 3 | key2 "value2" 4 | nestedKey { 5 | key3 "value3" 6 | key4 "value4" 7 | key5 { 8 | key6 "value6" 9 | } 10 | } 11 | } 12 | testblock2 { 13 | key1 "value1" 14 | key2 "value2" 15 | } 16 | testblock3 "not really" 17 | -------------------------------------------------------------------------------- /test/sample-data/test.compile.build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | testCompile( 3 | 'junit:junit:4.12', 4 | 'org.codehaus.groovy:groovy-all:2.4.10' 5 | ) 6 | 7 | testCompile([ 8 | 'org.jfrog.buildinfo:build-info-extractor-gradle:4.5.4', 9 | 'com.netflix.nebula:gradle-lint-plugin:latest.release'] 10 | ) 11 | 12 | testCompile(org.hibernate:hibernate-core:3.6.7.Final) 13 | } 14 | -------------------------------------------------------------------------------- /cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | 4 | var fs = require('fs'); 5 | var parser = require('./lib/parser'); 6 | var path = process.argv.slice(2).join(''); 7 | 8 | if (!path) { 9 | console.error('No input detected'); 10 | return; 11 | } 12 | 13 | if (fs.statSync(path)) { 14 | parser.parseFile(path).then(function(parsedValue) { 15 | console.log(JSON.stringify(parsedValue, '', 2)); 16 | }); 17 | } 18 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | on: 3 | push: 4 | branches: ['*'] 5 | pull_request: 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | strategy: 10 | matrix: 11 | node: ['12', '14', '16'] 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: actions/setup-node@v2 15 | with: 16 | node-version: ${{ matrix.node }} 17 | - run: yarn --frozen-lockfile 18 | - run: yarn test 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directory 27 | # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git 28 | node_modules/ 29 | 30 | # Optional npm cache directory 31 | .npm 32 | 33 | # Optional REPL history 34 | .node_repl_history 35 | 36 | .idea 37 | 38 | # Vim stuff 39 | *.swp 40 | 41 | # Other IDEs 42 | .vscode 43 | *.sublime-workspace 44 | 45 | # Misc 46 | .DS_Store 47 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gradle-to-js", 3 | "version": "2.0.1", 4 | "description": "A quick & dirty Gradle build file to JavaScript object parser", 5 | "main": "lib/parser.js", 6 | "bin": { 7 | "gradle-to-js": "./cli.js" 8 | }, 9 | "scripts": { 10 | "test": "mocha --reporter spec" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/ninetwozero/gradle-to-js.git" 15 | }, 16 | "keywords": [ 17 | "gradle", 18 | "javascript", 19 | "parsing" 20 | ], 21 | "files": [ 22 | "lib/", 23 | "cli.js" 24 | ], 25 | "author": "Karl Lindmark", 26 | "license": "Apache-2.0", 27 | "bugs": { 28 | "url": "https://github.com/ninetwozero/gradle-to-js/issues" 29 | }, 30 | "homepage": "https://github.com/ninetwozero/gradle-to-js#readme", 31 | "devDependencies": { 32 | "chai": "^4.2.0", 33 | "mocha": "^6.2.0", 34 | "multiline": "^2.0.0" 35 | }, 36 | "dependencies": { 37 | "lodash.merge": "^4.6.2" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test/sample-data/test.compile.build.gradle.expected.js: -------------------------------------------------------------------------------- 1 | exports.expected = { 2 | dependencies: [ 3 | { 4 | group: 'junit', 5 | name: 'junit', 6 | version: '4.12', 7 | type: 'testCompile', 8 | excludes: [] 9 | }, 10 | { 11 | group: 'org.codehaus.groovy', 12 | name: 'groovy-all', 13 | version: '2.4.10', 14 | type: 'org', 15 | excludes: [] 16 | }, 17 | { 18 | group: 'org.jfrog.buildinfo', 19 | name: 'build-info-extractor-gradle', 20 | version: '4.5.4', 21 | type: 'testCompile', 22 | excludes: [] 23 | }, 24 | { 25 | group: 'com.netflix.nebula', 26 | name: 'gradle-lint-plugin', 27 | version: 'latest.release', 28 | type: 'com', 29 | excludes: [] 30 | }, 31 | { 32 | group: 'org.hibernate', 33 | name: 'hibernate-core', 34 | version: '3.6.7.Final)', 35 | type: 'testCompile', 36 | excludes: [] 37 | } 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /test/sample-data/ivy.build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | dependencies { 17 | compile 'com.squareup.okhttp:okhttp:[2.1,3.0]' 18 | compile 'com.squareup.okhttp:okhttp-urlconnection:[2.1,3.0[' 19 | compile 'com.squareup.picasso:picasso:]1.0,4.0]' 20 | compile 'com.google.android.gms:play-services-wearable:]1.0,2.0[' 21 | compile 'de.greenrobot:eventbus:[1.0,)' 22 | compile 'com.android.support:appcompat-v7:]1.0,)' 23 | compile 'com.android.support:recyclerview-v7:(,2.0]' 24 | compile 'com.android.support:design:(,2.0[' 25 | compile 'com.android.support:customtabs:23.1.1' 26 | } 27 | -------------------------------------------------------------------------------- /test/sample-data/special.dependencies.build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | } 5 | dependencies { 6 | classpath some.classpath.entry 7 | } 8 | } 9 | 10 | dependencies { 11 | compile (project(':react-native-maps')) { 12 | exclude group: 'com.google.android.gms', module: 'play-services-base' 13 | exclude group: 'com.google.android.gms', module: 'play-services-maps' 14 | } 15 | testRuntime (project(':react-native-background-geolocation')) { 16 | exclude group: 'com.google.android.gms', module: 'play-services-location' 17 | } 18 | compile (group: 'g0', name: 'a0', version: 'v0') { 19 | exclude group: 'com.google.android.gms1' 20 | exclude module: 'play-services-location1' 21 | } 22 | compile (group: 'g0', name: 'a0', version: 'v0') { 23 | exclude group: 'com.google.android.gms1' 24 | exclude module: 'play-services-location1' 25 | } 26 | 27 | compile 'g1:a1:v1' 28 | runtime group: 'g2', name: 'a2', version: 'v2' 29 | compile('g3:a3:v3') { 30 | exclude group: 'com.google.android.gms', module: 'play-services-location' 31 | } 32 | 33 | compile('com.org.g4:org-a4:org-v4') 34 | testCompile (group: 'g5', name: 'a5', version: 'v5') 35 | 36 | // comment 37 | compile project(':project-behind-comment') 38 | compile project(':project-behind-comment2') 39 | 40 | devWearApp project(':wear') 41 | prodWearApp project(':wear') 42 | } 43 | -------------------------------------------------------------------------------- /test/sample-data/ivy.build.gradle.expected.js: -------------------------------------------------------------------------------- 1 | exports.expected = { 2 | dependencies: [ 3 | { 4 | group: 'com.squareup.okhttp', 5 | name: 'okhttp', 6 | version: '[2.1,3.0]', 7 | type: 'compile', 8 | excludes: [] 9 | }, 10 | { 11 | group: 'com.squareup.okhttp', 12 | name: 'okhttp-urlconnection', 13 | version: '[2.1,3.0[', 14 | type: 'compile', 15 | excludes: [] 16 | }, 17 | { 18 | group: 'com.squareup.picasso', 19 | name: 'picasso', 20 | version: ']1.0,4.0]', 21 | type: 'compile', 22 | excludes: [] 23 | }, 24 | { 25 | group: 'com.google.android.gms', 26 | name: 'play-services-wearable', 27 | version: ']1.0,2.0[', 28 | type: 'compile', 29 | excludes: [] 30 | }, 31 | { 32 | group: 'de.greenrobot', 33 | name: 'eventbus', 34 | version: '[1.0,)', 35 | type: 'compile', 36 | excludes: [] 37 | }, 38 | { 39 | group: 'com.android.support', 40 | name: 'appcompat-v7', 41 | version: ']1.0,)', 42 | type: 'compile', 43 | excludes: [] 44 | }, 45 | { 46 | group: 'com.android.support', 47 | name: 'recyclerview-v7', 48 | version: '(,2.0]', 49 | type: 'compile', 50 | excludes: [] 51 | }, 52 | { 53 | group: 'com.android.support', 54 | name: 'design', 55 | version: '(,2.0[', 56 | type: 'compile', 57 | excludes: [] 58 | }, 59 | { 60 | group: 'com.android.support', 61 | name: 'customtabs', 62 | version: '23.1.1', 63 | type: 'compile', 64 | excludes: [] 65 | } 66 | ] 67 | } 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gradle-to-js 2 | 3 | [![NPM Version](https://img.shields.io/npm/v/gradle-to-js.svg)](https://www.npmjs.com/package/gradle-to-js) 4 | [![Build Status][1]][2] 5 | 6 | ## What's this `gradle-to-js` thing? 7 | 8 | gradle-to-js is a quick & dirty Gradle build file to JavaScript object parser. It is quick & dirty in the sense that it doesn't give you an exact replica of whatever the build file represents during runtime, as evaluations and similar bits are (currently) too much of a hassle to accurately represent while parsing. 9 | 10 | ## Installation 11 | 12 | Simply run the following command to include it into your project: 13 | 14 | ```sh 15 | npm install gradle-to-js --save 16 | ``` 17 | 18 | ## Usage 19 | 20 | ### As a module 21 | 22 | Using `gradle-to-js` as a module, you can parse both strings and files as seen below. 23 | 24 | #### Files 25 | 26 | ```js 27 | var g2js = require('gradle-to-js/lib/parser'); 28 | g2js.parseFile('path/to/buildfile').then(function(representation) { 29 | console.log(representation); 30 | }); 31 | ``` 32 | 33 | #### Strings 34 | 35 | ```js 36 | var g2js = require('gradle-to-js/lib/parser'); 37 | g2js.parseText('key "value"').then(function(representation) { 38 | console.log(representation); 39 | }); 40 | ``` 41 | 42 | The promise will eventually resolve an object matching the build file structure and values. 43 | 44 | ### Using the CLI 45 | 46 | You can also use the module directly from the CLI, and get a json representation out of it. Nifty ey? Currently only supporting files from this direction. 47 | 48 | ```bash 49 | ./index.js test/sample-data/small.build.gradle 50 | ``` 51 | 52 | ```json 53 | { 54 | "testblock": { 55 | "key1": "value1", 56 | "key2": "value2", 57 | "nestedKey": { 58 | "key3": "value3", 59 | "key4": "value4", 60 | "key5": { 61 | "key6": "value6" 62 | } 63 | } 64 | }, 65 | "testblock2": { 66 | "key1": "value1", 67 | "key2": "value2" 68 | }, 69 | "testblock3": "not really" 70 | } 71 | ``` 72 | 73 | ## Author 74 | 75 | [Karl Lindmark](https://www.github.com/karllindmark) 76 | 77 | ## License 78 | 79 | Apache 2.0 80 | 81 | [1]: https://github.com/ninetwozero/gradle-to-js/workflows/ci/badge.svg 82 | [2]: https://github.com/ninetwozero/gradle-to-js/actions 83 | -------------------------------------------------------------------------------- /.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "requireCurlyBraces": [ 3 | "if", 4 | "else", 5 | "for", 6 | "while", 7 | "do", 8 | "try", 9 | "catch" 10 | ], 11 | "requireOperatorBeforeLineBreak": true, 12 | "requireCamelCaseOrUpperCaseIdentifiers": { 13 | "allowedPrefixes": ["opt_"], 14 | "allExcept": ["var_args"] 15 | }, 16 | "maxErrors": -1, 17 | "maximumLineLength": { 18 | "value": 80, 19 | "allExcept": ["comments", "regex"] 20 | }, 21 | "validateIndentation": 2, 22 | "validateQuoteMarks": "'", 23 | 24 | "disallowMultipleLineStrings": true, 25 | "disallowMixedSpacesAndTabs": true, 26 | "disallowTrailingWhitespace": true, 27 | "disallowSpaceAfterPrefixUnaryOperators": true, 28 | "disallowMultipleVarDecl": true, 29 | "disallowKeywordsOnNewLine": ["else"], 30 | 31 | "requireSpaceAfterKeywords": [ 32 | "if", 33 | "else", 34 | "for", 35 | "while", 36 | "do", 37 | "switch", 38 | "return", 39 | "try", 40 | "catch" 41 | ], 42 | "requireSpaceBeforeBinaryOperators": [ 43 | "=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=", 44 | "&=", "|=", "^=", "+=", 45 | 46 | "+", "-", "*", "/", "%", "<<", ">>", ">>>", "&", 47 | "|", "^", "&&", "||", "===", "==", ">=", 48 | "<=", "<", ">", "!=", "!==" 49 | ], 50 | "requireSpaceAfterBinaryOperators": true, 51 | "requireSpacesInConditionalExpression": true, 52 | "requireSpaceBeforeBlockStatements": true, 53 | "requireSpacesInForStatement": true, 54 | "requireLineFeedAtFileEnd": true, 55 | "requireSpacesInFunctionExpression": { 56 | "beforeOpeningCurlyBrace": true 57 | }, 58 | "disallowSpacesInAnonymousFunctionExpression": { 59 | "beforeOpeningRoundBrace": true 60 | }, 61 | "disallowSpacesInsideObjectBrackets": "all", 62 | "disallowSpacesInsideArrayBrackets": "all", 63 | "disallowSpacesInsideParentheses": true, 64 | 65 | "disallowMultipleLineBreaks": true, 66 | "disallowNewlineBeforeBlockStatements": true, 67 | "disallowKeywords": ["with"], 68 | "disallowSpacesInFunctionExpression": { 69 | "beforeOpeningRoundBrace": true 70 | }, 71 | "disallowSpacesInFunctionDeclaration": { 72 | "beforeOpeningRoundBrace": true 73 | }, 74 | "disallowSpacesInCallExpression": true, 75 | "disallowSpaceAfterObjectKeys": true, 76 | "requireSpaceBeforeObjectValues": true, 77 | "requireCapitalizedConstructors": true, 78 | "requireDotNotation": true, 79 | "requireSemicolons": true, 80 | "validateParameterSeparator": ", ", 81 | 82 | "jsDoc": { 83 | "checkAnnotations": "closurecompiler", 84 | "checkParamNames": true, 85 | "requireParamTypes": true, 86 | "checkRedundantParams": true, 87 | "checkReturnTypes": true, 88 | "checkRedundantReturns": true, 89 | "requireReturnTypes": true, 90 | "checkTypes": true, 91 | "checkRedundantAccess": true, 92 | "requireNewlineAfterDescription": true 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /test/sample-data/muzei.build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | buildscript { 18 | repositories { 19 | mavenCentral() 20 | } 21 | dependencies { 22 | classpath rootProject.ext.gradleClasspath 23 | } 24 | } 25 | 26 | apply plugin: 'com.android.application' 27 | 28 | project.archivesBaseName = "muzei" 29 | 30 | repositories { 31 | mavenCentral() 32 | } 33 | 34 | android { 35 | compileSdkVersion rootProject.ext.compileSdkVersion 36 | buildToolsVersion rootProject.ext.buildToolsVersion 37 | 38 | def Properties versionProps = new Properties() 39 | versionProps.load(new FileInputStream(file('../version.properties'))) 40 | 41 | defaultConfig { 42 | minSdkVersion 17 43 | targetSdkVersion rootProject.ext.targetSdkVersion 44 | renderscriptTargetApi rootProject.ext.targetSdkVersion 45 | renderscriptSupportModeEnabled true 46 | 47 | versionName versionProps['name'] 48 | versionCode versionProps['code'].toInteger() 49 | } 50 | 51 | signingConfigs { 52 | release { 53 | def Properties localProps = new Properties() 54 | localProps.load(new FileInputStream(file('../local.properties'))) 55 | def Properties keyProps = new Properties() 56 | if (localProps['keystore.props.file'] != null) { 57 | keyProps.load(new FileInputStream(file(localProps['keystore.props.file']))) 58 | } 59 | storeFile keyProps["store"] != null ? file(keyProps["store"]) : null 60 | keyAlias keyProps["alias"] ?: "" 61 | storePassword keyProps["storePass"] ?: "" 62 | keyPassword keyProps["pass"] ?: "" 63 | } 64 | } 65 | 66 | productFlavors { 67 | dev { 68 | // dev utilizes minSDKVersion = 21 to allow the Android gradle plugin 69 | // to pre-dex each module and produce an APK that can be tested on 70 | // Android Lollipop without time consuming dex merging processes. 71 | minSdkVersion 21 72 | multiDexEnabled true 73 | } 74 | 75 | prod { 76 | } 77 | } 78 | 79 | buildTypes { 80 | debug { 81 | versionNameSuffix " Debug" 82 | } 83 | 84 | release { 85 | minifyEnabled true 86 | shrinkResources true 87 | proguardFiles getDefaultProguardFile('proguard-android.txt'), file('proguard-project.txt') 88 | signingConfig signingConfigs.release 89 | } 90 | 91 | publicBeta.initWith(buildTypes.release) 92 | publicBeta { 93 | minifyEnabled true 94 | shrinkResources true 95 | proguardFiles getDefaultProguardFile('proguard-android.txt'), file('proguard-project.txt') 96 | versionNameSuffix " " + versionProps['betaNumber'] 97 | } 98 | 99 | publicDebug.initWith(buildTypes.publicBeta) 100 | publicDebug { 101 | debuggable true 102 | renderscriptDebuggable true 103 | minifyEnabled true 104 | shrinkResources true 105 | proguardFiles getDefaultProguardFile('proguard-android.txt'), file('proguard-project.txt') 106 | versionNameSuffix " Debug " + versionProps['betaNumber'] 107 | } 108 | } 109 | 110 | compileOptions { 111 | sourceCompatibility JavaVersion.VERSION_1_7 112 | targetCompatibility JavaVersion.VERSION_1_7 113 | } 114 | } 115 | 116 | dependencies { 117 | compile 'com.squareup.okhttp:okhttp:2.1.0' 118 | compile 'com.squareup.okhttp:okhttp-urlconnection:2.1.0' 119 | compile 'com.squareup.picasso:picasso:2.4.0' 120 | compile 'com.google.android.gms:play-services-wearable:8.3.0' 121 | compile 'de.greenrobot:eventbus:2.4.0' 122 | compile 'com.android.support:appcompat-v7:23.1.1' 123 | compile 'com.android.support:recyclerview-v7:23.1.1' 124 | compile 'com.android.support:design:23.1.1' 125 | compile 'com.android.support:customtabs:23.1.1' 126 | 127 | // :api is included as a transitive dependency from :android-client-common 128 | // compile project(':api') 129 | compile project(':android-client-common') 130 | devWearApp project(path: ':wearable', configuration: 'devRelease') 131 | prodWearApp project(path: ':wearable', configuration: 'prodRelease') 132 | } 133 | -------------------------------------------------------------------------------- /test/sample-data/muzei.build.gradle.expected.js: -------------------------------------------------------------------------------- 1 | exports.expected = { 2 | buildscript: { 3 | repositories: [ 4 | { 5 | data: { 6 | name: 'mavenCentral()' 7 | }, 8 | type: 'unknown' 9 | } 10 | ], 11 | dependencies: [ 12 | { 13 | group: '', 14 | name: 'rootProject.ext.gradleClasspath', 15 | version: '', 16 | type: 'classpath', 17 | excludes: [] 18 | } 19 | ] 20 | }, 21 | apply: 'plugin: \'com.android.application\'', 22 | 'project.archivesBaseName': 'muzei', 23 | 24 | repositories: [ 25 | { 26 | data: { 27 | name: 'mavenCentral()' 28 | }, 29 | type: 'unknown' 30 | } 31 | ], 32 | 33 | android: { 34 | compileSdkVersion: 'rootProject.ext.compileSdkVersion', 35 | buildToolsVersion: 'rootProject.ext.buildToolsVersion', 36 | 37 | versionProps: 'new Properties()', 38 | defaultConfig: { 39 | minSdkVersion: '17', 40 | targetSdkVersion: 'rootProject.ext.targetSdkVersion', 41 | renderscriptTargetApi: 'rootProject.ext.targetSdkVersion', 42 | renderscriptSupportModeEnabled: true, 43 | 44 | versionCode: 'versionProps[\'code\'].toInteger()', 45 | versionName: 'versionProps[\'name\']' 46 | }, 47 | 48 | signingConfigs: { 49 | release: { 50 | keyProps: 'new Properties()', 51 | localProps: 'new Properties()', 52 | 53 | storeFile: 'keyProps["store"] != null ? file(keyProps["store"]) : null', 54 | keyAlias: 'keyProps["alias"] ?: ""', 55 | storePassword: 'keyProps["storePass"] ?: ""', 56 | keyPassword: 'keyProps["pass"] ?: ""' 57 | } 58 | }, 59 | 60 | productFlavors: { 61 | dev: { 62 | minSdkVersion: '21', 63 | multiDexEnabled: true 64 | }, 65 | prod: {} 66 | }, 67 | 68 | buildTypes: { 69 | debug: { 70 | versionNameSuffix: ' Debug' 71 | }, 72 | release: { 73 | minifyEnabled: true, 74 | shrinkResources: true, 75 | proguardFiles: 'getDefaultProguardFile(\'proguard-android.txt\'), file(\'proguard-project.txt\')', 76 | signingConfig: 'signingConfigs.release' 77 | }, 78 | publicBeta: { 79 | minifyEnabled: true, 80 | shrinkResources: true, 81 | proguardFiles: 'getDefaultProguardFile(\'proguard-android.txt\'), file(\'proguard-project.txt\')', 82 | versionNameSuffix: '" " + versionProps[\'betaNumber\']' 83 | }, 84 | publicDebug: { 85 | debuggable: true, 86 | renderscriptDebuggable: true, 87 | minifyEnabled: true, 88 | shrinkResources: true, 89 | proguardFiles: 'getDefaultProguardFile(\'proguard-android.txt\'), file(\'proguard-project.txt\')', 90 | versionNameSuffix: '" Debug " + versionProps[\'betaNumber\']' 91 | } 92 | }, 93 | 94 | compileOptions: { 95 | sourceCompatibility: 'JavaVersion.VERSION_1_7', 96 | targetCompatibility: 'JavaVersion.VERSION_1_7' 97 | } 98 | }, 99 | 100 | dependencies: [ 101 | { 102 | group: 'com.squareup.okhttp', 103 | name: 'okhttp', 104 | version: '2.1.0', 105 | type: 'compile', 106 | excludes: [] 107 | }, 108 | { 109 | group: 'com.squareup.okhttp', 110 | name: 'okhttp-urlconnection', 111 | version: '2.1.0', 112 | type: 'compile', 113 | excludes: [] 114 | }, 115 | { 116 | group: 'com.squareup.picasso', 117 | name: 'picasso', 118 | version: '2.4.0', 119 | type: 'compile', 120 | excludes: [] 121 | }, 122 | { 123 | group: 'com.google.android.gms', 124 | name: 'play-services-wearable', 125 | version: '8.3.0', 126 | type: 'compile', 127 | excludes: [] 128 | }, 129 | { 130 | group: 'de.greenrobot', 131 | name: 'eventbus', 132 | version: '2.4.0', 133 | type: 'compile', 134 | excludes: [] 135 | }, 136 | { 137 | group: 'com.android.support', 138 | name: 'appcompat-v7', 139 | version: '23.1.1', 140 | type: 'compile', 141 | excludes: [] 142 | }, 143 | { 144 | group: 'com.android.support', 145 | name: 'recyclerview-v7', 146 | version: '23.1.1', 147 | type: 'compile', 148 | excludes: [] 149 | }, 150 | { 151 | group: 'com.android.support', 152 | name: 'design', 153 | version: '23.1.1', 154 | type: 'compile', 155 | excludes: [] 156 | }, 157 | { 158 | group: 'com.android.support', 159 | name: 'customtabs', 160 | version: '23.1.1', 161 | type: 'compile', 162 | excludes: [] 163 | }, 164 | { 165 | group: '', 166 | name: 'project(\':android-client-common\')', 167 | version: '', 168 | type: 'compile', 169 | excludes: [] 170 | }, 171 | { 172 | group: '', 173 | name: 'project(path: \':wearable\', configuration: \'devRelease\')', 174 | version: '', 175 | type: 'devWearApp', 176 | excludes: [] 177 | }, 178 | { 179 | group: '', 180 | name: 'project(path: \':wearable\', configuration: \'prodRelease\')', 181 | version: '', 182 | type: 'prodWearApp', 183 | excludes: [] 184 | } 185 | ] 186 | } 187 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /test/parser.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var expect = require('chai').expect; 3 | var multiline = require('multiline'); 4 | 5 | var parser = require('../lib/parser'); 6 | 7 | describe('Gradle build file parser', function() { 8 | describe('(text parsing)', function() { 9 | it('can parse a single <>', function() { 10 | var dsl = 'key "value"'; 11 | var expected = {key: 'value'}; 12 | 13 | return parser.parseText(dsl).then(function(parsedValue) { 14 | expect(parsedValue).to.deep.equal(expected); 15 | }); 16 | }); 17 | 18 | it('can parse a single key=value', function() { 19 | var dsl = 'key = "value"'; 20 | var expected = {key: 'value'}; 21 | return parser.parseText(dsl).then(function(parsedValue) { 22 | expect(parsedValue).to.deep.equal(expected); 23 | }); 24 | }); 25 | 26 | it('can parse a multiple <> combinations', function() { 27 | var dsl = multiline.stripIndent(function() {/* 28 | key "value" 29 | key2 "value2" 30 | */ 31 | }); 32 | var expected = {key: 'value', key2: 'value2'}; 33 | 34 | return parser.parseText(dsl).then(function(parsedValue) { 35 | expect(parsedValue).to.deep.equal(expected); 36 | }); 37 | }); 38 | 39 | it('can parse a multiple <> combinations', function() { 40 | var dsl = multiline.stripIndent(function() {/* 41 | key = "value" 42 | key2 = "value2" 43 | */ 44 | }); 45 | var expected = {key: 'value', key2: 'value2'}; 46 | 47 | return parser.parseText(dsl).then(function(parsedValue) { 48 | expect(parsedValue).to.deep.equal(expected); 49 | }); 50 | }); 51 | 52 | it('can detect a block', function() { 53 | var dsl = multiline.stripIndent(function() {/* 54 | testblock { 55 | 56 | } 57 | */ 58 | }); 59 | var expected = {testblock: {}}; 60 | 61 | return parser.parseText(dsl).then(function(parsedValue) { 62 | expect(parsedValue).to.deep.equal(expected); 63 | }); 64 | 65 | }); 66 | 67 | it('can detect a single level block and its values', function() { 68 | var dsl = multiline.stripIndent(function() {/* 69 | testblock { 70 | key1 "value1" 71 | key2 "value2" 72 | } 73 | */ 74 | }); 75 | var expected = {testblock: {key1: 'value1', key2: 'value2'}}; 76 | 77 | return parser.parseText(dsl).then(function(parsedValue) { 78 | expect(parsedValue).to.deep.equal(expected); 79 | }); 80 | 81 | }); 82 | 83 | it('can detect a multiple single level block and their values', function() { 84 | var dsl = multiline.stripIndent(function() {/* 85 | testblock { 86 | key1 "value1" 87 | key2 "value2" 88 | } 89 | testblock2 { 90 | key3 "value3" 91 | key4 "value4" 92 | } 93 | */ 94 | }); 95 | var expected = { 96 | testblock: {key1: 'value1', key2: 'value2'}, 97 | testblock2: {key3: 'value3', key4: 'value4'} 98 | }; 99 | 100 | return parser.parseText(dsl).then(function(parsedValue) { 101 | expect(parsedValue).to.deep.equal(expected); 102 | }); 103 | 104 | }); 105 | 106 | it('can detect a mix of single level items', function() { 107 | var dsl = multiline.stripIndent(function() {/* 108 | testblock { 109 | key1 "value1" 110 | key2 "value2" 111 | } 112 | testblock3 "not really" 113 | testblock2 { 114 | key3 "value3" 115 | key4 "value4" 116 | } 117 | */ 118 | }); 119 | var expected = { 120 | testblock: {key1: 'value1', key2: 'value2'}, 121 | testblock2: {key3: 'value3', key4: 'value4'}, 122 | testblock3: 'not really' 123 | }; 124 | 125 | return parser.parseText(dsl).then(function(parsedValue) { 126 | expect(parsedValue).to.deep.equal(expected); 127 | }); 128 | 129 | }); 130 | 131 | it('can detect chaos', function() { 132 | var dsl = multiline.stripIndent(function() {/* 133 | testblock { 134 | key1 "value1" 135 | key2 "value2" 136 | nestedKey { 137 | key3 "value3" 138 | key4 "value4" 139 | key5 { 140 | key6 "value6" 141 | } 142 | } 143 | } 144 | testblock2 { 145 | key1 "value1" 146 | key2 "value2" 147 | } 148 | testblock3 "not really" 149 | */ 150 | }); 151 | var expected = { 152 | testblock: { 153 | key1: 'value1', 154 | key2: 'value2', 155 | nestedKey: { 156 | key3: 'value3', 157 | key4: 'value4', 158 | key5: { 159 | key6: 'value6' 160 | } 161 | } 162 | }, 163 | testblock2: {key1: 'value1', key2: 'value2'}, 164 | testblock3: 'not really' 165 | }; 166 | return parser.parseText(dsl).then(function(parsedValue) { 167 | expect(parsedValue).to.deep.equal(expected); 168 | }); 169 | 170 | }); 171 | 172 | it('will skip commented lines', function() { 173 | var dsl = 'key "value"' + '\n'; 174 | dsl += '// this is a single line comment' + '\n'; 175 | dsl += 'key2 "value2"' + '\n'; 176 | dsl += '/* this is a multi' + '\n'; 177 | dsl += 'line comment */' + '\n'; 178 | dsl += ' key3 "value3"' + '\n'; 179 | dsl += '/**' + '\n'; 180 | dsl += ' *' + '\n'; 181 | dsl += ' * Something here' + '\n'; 182 | dsl += ' *' + '\n'; 183 | dsl += ' */'; 184 | 185 | var expected = {key: 'value', key2: 'value2', key3: 'value3'}; 186 | return parser.parseText(dsl).then(function(parsedValue) { 187 | expect(parsedValue).to.deep.equal(expected); 188 | }); 189 | }); 190 | it('will store multiple occurences of a key as an array', function() { 191 | var dsl = multiline.stripIndent(function() {/* 192 | testblock { 193 | key1 "value1" 194 | key1 "value2" 195 | } 196 | key1 "value3" 197 | key1 "value4" 198 | */ }); 199 | 200 | var expected = { 201 | testblock: { 202 | key1: ['value1', 'value2'] 203 | }, 204 | key1: ['value3', 'value4'] 205 | }; 206 | return parser.parseText(dsl).then(function(parsedValue) { 207 | expect(parsedValue).to.deep.equal(expected); 208 | }); 209 | }); 210 | 211 | it('will be able to parse a list of items', function() { 212 | var dsl = multiline.stripIndent(function() {/* 213 | testblock { 214 | key1 ["value1", "value2"] 215 | } 216 | key1 ["value3", "value4"] 217 | specialKey " " + key1["sausage"] 218 | */ }); 219 | 220 | var expected = { 221 | testblock: { 222 | key1: ['value1', 'value2'] 223 | }, 224 | key1: ['value3', 'value4'], 225 | specialKey: '" " + key1["sausage"]' 226 | }; 227 | return parser.parseText(dsl).then(function(parsedValue) { 228 | expect(parsedValue).to.deep.equal(expected); 229 | }); 230 | }); 231 | 232 | // Because the scoping that def imposes doesn't make a difference for us 233 | it('should be able to collect definitions as regular variables', function() { 234 | var dsl = multiline.stripIndent(function() {/* 235 | def myVar1 = new Var() 236 | def myVar2 = new Var(2) 237 | */ }); 238 | 239 | var expected = { 240 | myVar1: 'new Var()', 241 | myVar2: 'new Var(2)' 242 | }; 243 | return parser.parseText(dsl).then(function(parsedValue) { 244 | expect(parsedValue).to.deep.equal(expected); 245 | }); 246 | }); 247 | 248 | it('should be able to collect complex definitions as regular variables', function() { 249 | var dsl = multiline.stripIndent(function() {/* 250 | def MyType myVar1 = new Var() 251 | def MyType myVar2 = new Var(2) 252 | */ }); 253 | 254 | var expected = { 255 | myVar1: 'new Var()', 256 | myVar2: 'new Var(2)' 257 | }; 258 | return parser.parseText(dsl).then(function(parsedValue) { 259 | expect(parsedValue).to.deep.equal(expected); 260 | }); 261 | }); 262 | 263 | it('should skip (seemingly) function calls to variables', function() { 264 | var dsl = multiline.stripIndent(function() {/* 265 | def MyType myVar1 = new Var() 266 | myVar1.loadSomething(new Cake()) 267 | */ }); 268 | 269 | var expected = { 270 | myVar1: 'new Var()' 271 | }; 272 | return parser.parseText(dsl).then(function(parsedValue) { 273 | expect(parsedValue).to.deep.equal(expected); 274 | }); 275 | }); 276 | 277 | it('should group repositories into an array', function() { 278 | var dsl = multiline.stripIndent(function() {/* 279 | repositories { 280 | mavenCentral() 281 | maven { 282 | url "http://test" 283 | } 284 | } 285 | */}); 286 | 287 | var expected = { 288 | repositories: [ 289 | {type: 'unknown', data: {name: 'mavenCentral()'}}, 290 | {type: 'maven', data: {url: 'http://test'}} 291 | ] 292 | }; 293 | return parser.parseText(dsl).then(function(parsedValue) { 294 | expect(parsedValue).to.deep.equal(expected); 295 | }); 296 | }); 297 | 298 | it('should group plugins into an array with a given format', function() { 299 | var dsl = multiline.stripIndent(function() {/* 300 | plugins { 301 | id 'some.id.here' version 'some.version.here' 302 | id 'another.id.here' 303 | version 'some.other.version.here' id 'some.other.id.here' 304 | id "plugin.id.doublequotes" 305 | id 'id.with.hyphen-symbol' 306 | id 'id.with.underscore_symbol' 307 | id ('plugin.id.parens') 308 | id ('plugin.id.parens.version') version '1.2.3' 309 | } 310 | */}); 311 | 312 | var expected = { 313 | plugins: [ 314 | {id: 'some.id.here', version: 'some.version.here'}, 315 | {id: 'another.id.here'}, 316 | {id: 'some.other.id.here', version: 'some.other.version.here'}, 317 | {id: 'plugin.id.doublequotes'}, 318 | {id: 'id.with.hyphen-symbol'}, 319 | {id: 'id.with.underscore_symbol'}, 320 | {id: 'plugin.id.parens'}, 321 | {id: 'plugin.id.parens.version', version: '1.2.3'} 322 | ] 323 | }; 324 | return parser.parseText(dsl).then(function(parsedValue) { 325 | expect(parsedValue).to.deep.equal(expected); 326 | }); 327 | }); 328 | 329 | it('should be able to parse booleans into booleans', function() { 330 | var dsl = multiline.stripIndent(function() {/* 331 | myVar1 true 332 | someAttribute true 333 | someFalseAttribute false 334 | myVar2 false 335 | */ 336 | }); 337 | 338 | var expected = { 339 | myVar1: true, 340 | someAttribute: true, 341 | someFalseAttribute: false, 342 | myVar2: false 343 | }; 344 | return parser.parseText(dsl).then(function(parsedValue) { 345 | expect(parsedValue).to.deep.equal(expected); 346 | }); 347 | }); 348 | 349 | it('should parse numbers as strings', function() { 350 | var dsl = multiline.stripIndent(function() {/* 351 | myVar301 1 352 | myVar402 32 353 | myVar103 33 354 | myVar204 4 355 | */ }); 356 | 357 | var expected = { 358 | myVar301: '1', 359 | myVar402: '32', 360 | myVar103: '33', 361 | myVar204: '4' 362 | }; 363 | return parser.parseText(dsl).then(function(parsedValue) { 364 | expect(parsedValue).to.deep.equal(expected); 365 | }); 366 | }); 367 | it('can skip if blocks', function() { 368 | var dsl = multiline.stripIndent(function() {/* 369 | myVar1 "a" 370 | if (myVar301 === "sausage") { 371 | myVar2 "b" 372 | } 373 | myVar2 "c" 374 | */ }); 375 | 376 | var expected = { 377 | myVar1: 'a', 378 | myVar2: 'c' 379 | }; 380 | return parser.parseText(dsl).then(function(parsedValue) { 381 | expect(parsedValue).to.deep.equal(expected); 382 | }); 383 | }); 384 | 385 | it('can skip if clauses without brackets', function() { 386 | var dsl = multiline.stripIndent(function() {/* 387 | myVar1 "a" 388 | if (myBreakfast === "eggs") myVar1 "b" 389 | myVar2 "c" 390 | if (myBreakfast === "bacon") 391 | myVar2 "d" 392 | */ }); 393 | 394 | var expected = { 395 | myVar1: 'a', 396 | myVar2: 'c' 397 | }; 398 | return parser.parseText(dsl).then(function(parsedValue) { 399 | expect(parsedValue).to.deep.equal(expected); 400 | }); 401 | }); 402 | 403 | it('can skip function definitions', function() { 404 | var dsl = multiline.stripIndent(function() {/* 405 | myVar1 "a" 406 | def fibonacci (int i) { 407 | if (i <= 2) { 408 | return 1; 409 | } else { 410 | return fibonacci(i - 1) + fibonacci(i - 2); 411 | } 412 | } 413 | myVar2 "c" 414 | */ }); 415 | 416 | var expected = { 417 | myVar1: 'a', 418 | myVar2: 'c' 419 | }; 420 | return parser.parseText(dsl).then(function(parsedValue) { 421 | expect(parsedValue).to.deep.equal(expected); 422 | }); 423 | }); 424 | 425 | it('will manage to parse closures that have brackets on another line', function() { 426 | var dsl = multiline.stripIndent(function() {/* 427 | android { 428 | property1 'one' 429 | } 430 | 431 | android 432 | { 433 | property2 'two' 434 | } 435 | */}); 436 | 437 | var expected = { android: { property1: 'one', property2: 'two'} }; 438 | return parser.parseText(dsl).then(function(parsedValue) { 439 | expect(parsedValue).to.deep.equal(expected); 440 | }); 441 | }); 442 | 443 | it('will merge multiple closures with the same key into one', function() { 444 | var dsl = multiline.stripIndent(function() {/* 445 | android { 446 | property1 'one' 447 | } 448 | 449 | android { 450 | property2 'two' 451 | } 452 | 453 | android { 454 | property3 'three' 455 | } 456 | */}); 457 | 458 | var expected = { android: { property1: 'one', property2: 'two', property3: 'three' } }; 459 | return parser.parseText(dsl).then(function(parsedValue) { 460 | expect(parsedValue).to.deep.equal(expected); 461 | }); 462 | }); 463 | it('will deep merge multiple complex closures with the same key into one', function() { 464 | var dsl = multiline.stripIndent(function() {/* 465 | foo { 466 | android { 467 | property1 'one' 468 | } 469 | 470 | android { 471 | property2 'two' 472 | } 473 | 474 | android { 475 | property3 'three' 476 | } 477 | 478 | android { 479 | property4 'four' 480 | } 481 | } 482 | */}); 483 | 484 | var expected = {foo: { android: { property1: 'one', property2: 'two', property3: 'three', property4: 'four' } } }; 485 | return parser.parseText(dsl).then(function(parsedValue) { 486 | expect(parsedValue).to.deep.equal(expected); 487 | }); 488 | }); 489 | 490 | it('will handle compile keywords separately', function() { 491 | var dsl = multiline.stripIndent(function() {/* 492 | dependencies { 493 | compile (project(':react-native-maps')) { 494 | exclude group: 'com.google.android.gms', module: 'play-services-base' 495 | exclude group: 'com.google.android.gms', module: 'play-services-maps' 496 | } 497 | compile (project(':react-native-background-geolocation')) { 498 | exclude group: 'com.google.android.gms', module: 'play-services-location' 499 | } 500 | compile 'g1:a1:v1' 501 | compile group: 'g2', name: 'a2', version: 'v2' 502 | } 503 | */}); 504 | 505 | var expected = { 506 | dependencies: [ 507 | { 508 | group: '', 509 | name: 'project(\':react-native-maps\')', 510 | version: '', 511 | type: 'compile', 512 | excludes: [ 513 | { 514 | group: 'com.google.android.gms', 515 | module: 'play-services-base' 516 | }, 517 | { 518 | group: 'com.google.android.gms', 519 | module: 'play-services-maps' 520 | } 521 | ] 522 | }, 523 | { 524 | group: '', 525 | name: 'project(\':react-native-background-geolocation\')', 526 | version: '', 527 | type: 'compile', 528 | excludes: [ 529 | { 530 | group: 'com.google.android.gms', 531 | module: 'play-services-location' 532 | } 533 | ] 534 | }, 535 | { 536 | group: 'g1', 537 | name: 'a1', 538 | version: 'v1', 539 | type: 'compile', 540 | excludes: [] 541 | }, 542 | { 543 | group: 'g2', 544 | name: 'a2', 545 | version: 'v2', 546 | type: 'compile', 547 | excludes: [] 548 | } 549 | ] 550 | }; 551 | 552 | return parser.parseText(dsl).then(function(parsedValue) { 553 | expect(parsedValue).to.deep.equal(expected); 554 | }); 555 | }); 556 | 557 | it('can handle Windows style CRLF gradle files accordingly', function() { 558 | var sampleFilePath = 'test/sample-data/windows_crlf.gradle'; 559 | var expected = require(process.cwd() + '/test/sample-data/windows_crlf.gradle.expected.js').expected; 560 | 561 | return parser.parseFile(sampleFilePath).then(function(parsedValue) { 562 | expect(parsedValue).to.deep.equal(expected); 563 | }); 564 | }); 565 | // TODO: Add test for ... 566 | }); 567 | describe('(file parsing)', function() { 568 | it('should be able to parse the small sample gradle file', function() { 569 | var sampleFilePath = 'test/sample-data/small.build.gradle'; 570 | var expected = { 571 | testblock: { 572 | key1: 'value1', 573 | key2: 'value2', 574 | nestedKey: { 575 | key3: 'value3', 576 | key4: 'value4', 577 | key5: { 578 | key6: 'value6' 579 | } 580 | } 581 | }, 582 | testblock2: {key1: 'value1', key2: 'value2'}, 583 | testblock3: 'not really' 584 | }; 585 | return parser.parseFile(sampleFilePath).then(function(parsedValue) { 586 | expect(parsedValue).to.deep.equal(expected); 587 | }); 588 | }); 589 | 590 | it('should be able to parse the muzei gradle file', function() { 591 | var sampleFilePath = 'test/sample-data/muzei.build.gradle'; 592 | var expected = require(process.cwd() + '/test/sample-data/muzei.build.gradle.expected.js').expected; 593 | 594 | return parser.parseFile(sampleFilePath).then(function(parsedValue) { 595 | expect(parsedValue).to.deep.equal(expected); 596 | }); 597 | }); 598 | 599 | it('should be able to parse the ivy gradle file', function() { 600 | var sampleFilePath = 'test/sample-data/ivy.build.gradle'; 601 | var expected = require(process.cwd() + '/test/sample-data/ivy.build.gradle.expected.js').expected; 602 | 603 | return parser.parseFile(sampleFilePath).then(function(parsedValue) { 604 | expect(parsedValue).to.deep.equal(expected); 605 | }); 606 | }); 607 | 608 | it('should be able to parse the testCompile with multiline gradle file', function() { 609 | var sampleFilePath = 'test/sample-data/test.compile.build.gradle'; 610 | var expected = require(process.cwd() + '/test/sample-data/test.compile.build.gradle.expected.js').expected; 611 | 612 | return parser.parseFile(sampleFilePath).then(function(parsedValue) { 613 | expect(parsedValue).to.deep.equal(expected); 614 | }); 615 | }); 616 | }); 617 | }); 618 | -------------------------------------------------------------------------------- /lib/parser.js: -------------------------------------------------------------------------------- 1 | /* jshint node: true */ 2 | 'use strict'; 3 | var stream = require('stream'); 4 | var fs = require('fs'); 5 | var deepAssign = require('lodash.merge') 6 | 7 | var exports = module.exports = {}; 8 | 9 | var CHAR_TAB = 9; 10 | var CHAR_NEWLINE = 10; 11 | var CHAR_CARRIAGE_RETURN = 13; 12 | var CHAR_SPACE = 32; 13 | var CHAR_LEFT_PARENTHESIS = 40; 14 | var CHAR_RIGHT_PARENTHESIS = 41; 15 | var CHAR_PERIOD = 46; 16 | var CHAR_SLASH = 47; 17 | var CHAR_EQUALS = 61; 18 | var CHAR_ARRAY_START = 91; 19 | var CHAR_ARRAY_END = 93; 20 | var CHAR_BLOCK_START = 123; 21 | var CHAR_BLOCK_END = 125; 22 | 23 | var KEYWORD_DEF = 'def'; 24 | var KEYWORD_IF = 'if'; 25 | 26 | var WHITESPACE_CHARACTERS = {}; 27 | WHITESPACE_CHARACTERS[CHAR_TAB] = true; 28 | WHITESPACE_CHARACTERS[CHAR_NEWLINE] = true; 29 | WHITESPACE_CHARACTERS[CHAR_CARRIAGE_RETURN] = true; 30 | WHITESPACE_CHARACTERS[CHAR_SPACE] = true; 31 | 32 | var SINGLE_LINE_COMMENT_START = '//'; 33 | var BLOCK_COMMENT_START = '/*'; 34 | var BLOCK_COMMENT_END = '*/'; 35 | 36 | var SPECIAL_KEYS = { 37 | repositories: parseRepositoryClosure, 38 | dependencies: parseDependencyClosure, 39 | plugins: parsePluginsClosure 40 | }; 41 | 42 | var DEPS_KEYWORD_STRING_PATTERN = '[ \\t]*([A-Za-z0-9_-]+)[ \\t]*'; 43 | var DEPS_KEYWORD_STRING_REGEX = RegExp(DEPS_KEYWORD_STRING_PATTERN); 44 | var DEPS_EASY_GAV_STRING_REGEX = RegExp('(["\']?)([\\w.-]+):([\\w.-]+):([\\w\\[\\]\\(\\),+.-]+)\\1'); 45 | var DEPS_HARD_GAV_STRING_REGEX = RegExp(DEPS_KEYWORD_STRING_PATTERN + '(?:\\((.*)\\)|(.*))'); 46 | var DEPS_ITEM_BLOCK_REGEX = RegExp(DEPS_KEYWORD_STRING_PATTERN + '\\(((["\']?)(.*)\\3)\\)[ \\t]*\\{'); 47 | var DEPS_EXCLUDE_LINE_REGEX = RegExp('exclude[ \\t]+([^\\n]+)', 'g'); 48 | var PLUGINS_LINE_PATTERN = RegExp('(id|version)[ \\t]*\\(?(["\']?)([A-Za-z0-9._-]+)\\2\\)?', 'g'); 49 | 50 | 51 | function deepParse(chunk, state, keepFunctionCalls, skipEmptyValues) { 52 | var out = {}; 53 | 54 | var chunkLength = chunk.length; 55 | var character = 0; 56 | var tempString = ''; 57 | var commentText = ''; 58 | 59 | var currentKey = ''; 60 | var parsingKey = true; 61 | var isBeginningOfLine = true; 62 | 63 | if (typeof skipEmptyValues === 'undefined') { 64 | skipEmptyValues = true; 65 | } 66 | 67 | for (; state.index < chunkLength; state.index++) { 68 | character = chunk[state.index]; 69 | 70 | if (isBeginningOfLine && isWhitespace(character)) { 71 | continue; 72 | } 73 | 74 | if (!state.comment.parsing && isBeginningOfLine && isStartOfComment(tempString)) { 75 | isBeginningOfLine = false; 76 | if (isSingleLineComment(tempString)) { 77 | state.comment.setSingleLine(); 78 | } else { 79 | state.comment.setMultiLine(); 80 | } 81 | continue; 82 | } 83 | 84 | if (state.comment.multiLine && isEndOfMultiLineComment(commentText)) { 85 | state.comment.reset(); 86 | 87 | isBeginningOfLine = true; 88 | tempString = ''; 89 | commentText = ''; 90 | continue; 91 | } 92 | 93 | if (state.comment.parsing && character != CHAR_NEWLINE) { 94 | commentText += String.fromCharCode(character); 95 | continue; 96 | } 97 | 98 | if (state.comment.parsing && isLineBreakCharacter(character)) { 99 | if (state.comment.singleLine) { 100 | state.comment.reset(); 101 | isBeginningOfLine = true; 102 | 103 | currentKey = ''; 104 | tempString = ''; 105 | commentText = ''; 106 | continue; 107 | } else { 108 | // NO-OP 109 | continue; 110 | } 111 | } 112 | 113 | if (parsingKey && !keepFunctionCalls && character === CHAR_LEFT_PARENTHESIS) { 114 | skipFunctionCall(chunk, state); 115 | currentKey = ''; 116 | tempString = ''; 117 | isBeginningOfLine = true; 118 | continue; 119 | } 120 | 121 | if (isLineBreakCharacter(character)) { 122 | if (!currentKey && tempString) { 123 | if (parsingKey) { 124 | if (isFunctionCall(tempString) && !keepFunctionCalls) { 125 | continue; 126 | } else { 127 | currentKey = tempString.trim(); 128 | tempString = ''; 129 | } 130 | } 131 | } 132 | 133 | if (tempString || (currentKey && !skipEmptyValues)) { 134 | addValueToStructure(out, currentKey, trimWrappingQuotes(tempString)); 135 | 136 | currentKey = ''; 137 | tempString = ''; 138 | } 139 | 140 | parsingKey = true; 141 | isBeginningOfLine = true; 142 | 143 | state.comment.reset(); 144 | continue; 145 | } 146 | 147 | // Only parse as an array if the first *real* char is a [ 148 | if (!parsingKey && !tempString && character === CHAR_ARRAY_START) { 149 | out[currentKey] = parseArray(chunk, state); 150 | currentKey = ''; 151 | tempString = ''; 152 | continue; 153 | } 154 | 155 | if (character === CHAR_BLOCK_START) { 156 | // We need to skip the current (=start) character so that we literally "step into" the next closure/block 157 | state.index++; 158 | 159 | if (SPECIAL_KEYS.hasOwnProperty(currentKey)) { 160 | out[currentKey] = SPECIAL_KEYS[currentKey](chunk, state); 161 | } else if (out[currentKey]) { 162 | out[currentKey] = deepAssign({}, out[currentKey], deepParse(chunk, state, keepFunctionCalls, skipEmptyValues)); 163 | } else { 164 | out[currentKey] = deepParse(chunk, state, keepFunctionCalls, skipEmptyValues); 165 | } 166 | currentKey = ''; 167 | } else if (character === CHAR_BLOCK_END) { 168 | currentKey = ''; 169 | tempString = ''; 170 | break; 171 | } else if (isDelimiter(character) && parsingKey) { 172 | if (isKeyword(tempString)) { 173 | if (tempString === KEYWORD_DEF) { 174 | tempString = fetchDefinedNameOrSkipFunctionDefinition(chunk, state); 175 | } else if (tempString === KEYWORD_IF) { 176 | skipIfStatement(chunk, state); 177 | currentKey = ''; 178 | tempString = ''; 179 | continue; 180 | } 181 | } 182 | 183 | currentKey = tempString; 184 | tempString = ''; 185 | parsingKey = false; 186 | if (!currentKey) { 187 | continue; 188 | } 189 | } else { 190 | if (!tempString && isDelimiter(character)) { 191 | continue; 192 | } 193 | tempString += String.fromCharCode(character); 194 | isBeginningOfLine = isBeginningOfLine && (character === CHAR_SLASH || isStartOfComment(tempString)); 195 | } 196 | } 197 | 198 | // Add the last value to the structure 199 | addValueToStructure(out, currentKey, trimWrappingQuotes(tempString)); 200 | return out; 201 | } 202 | 203 | function skipIfStatement(chunk, state) { 204 | skipFunctionCall(chunk, state); 205 | 206 | var character = ''; 207 | var hasFoundTheCurlyBraces = false; 208 | var hasFoundAStatementWithoutBraces = false; 209 | var curlyBraceCount = 0; 210 | 211 | for (var max = chunk.length; state.index < max; state.index++) { 212 | character = chunk[state.index]; 213 | 214 | if (hasFoundAStatementWithoutBraces) { 215 | if (isLineBreakCharacter(character)) { 216 | break; 217 | } 218 | } else { 219 | if (character === CHAR_BLOCK_START) { 220 | hasFoundTheCurlyBraces = true; 221 | curlyBraceCount++; 222 | } else if (character === CHAR_BLOCK_END) { 223 | curlyBraceCount--; 224 | } else if (!hasFoundTheCurlyBraces && !isWhitespace(character)) { 225 | hasFoundAStatementWithoutBraces = true; 226 | } 227 | 228 | if ((hasFoundTheCurlyBraces && curlyBraceCount === 0)) { 229 | break; 230 | } 231 | } 232 | } 233 | return curlyBraceCount === 0; 234 | } 235 | 236 | function skipFunctionDefinition(chunk, state) { 237 | var start = state.index; 238 | var parenthesisNest = 1; 239 | var character = chunk[++state.index]; 240 | while (character !== undefined && parenthesisNest) { 241 | if (character === CHAR_LEFT_PARENTHESIS) { 242 | parenthesisNest++; 243 | } else if (character === CHAR_RIGHT_PARENTHESIS) { 244 | parenthesisNest--; 245 | } 246 | 247 | character = chunk[++state.index]; 248 | } 249 | 250 | while (character && character !== CHAR_BLOCK_START) { 251 | character = chunk[++state.index]; 252 | } 253 | 254 | character = chunk[++state.index]; 255 | var blockNest = 1; 256 | while (character !== undefined && blockNest) { 257 | if (character === CHAR_BLOCK_START) { 258 | blockNest++; 259 | } else if (character === CHAR_BLOCK_END) { 260 | blockNest--; 261 | } 262 | 263 | character = chunk[++state.index]; 264 | } 265 | 266 | state.index--; 267 | } 268 | 269 | function parseDependencyClosure(chunk, state) { 270 | return parseSpecialClosure(chunk, state, createStructureForDependencyItem); 271 | } 272 | 273 | function createStructureForDependencyItem(data) { 274 | var out = { group: '', name: '', version: '', type: '' }; 275 | var compileBlockInfo = findDependencyItemBlock(data); 276 | if (compileBlockInfo['gav']) { 277 | out = parseGavString(compileBlockInfo['gav']); 278 | out['type'] = compileBlockInfo['type']; 279 | out['excludes'] = compileBlockInfo['excludes']; 280 | } else { 281 | out = parseGavString(data); 282 | var parsed = DEPS_KEYWORD_STRING_REGEX.exec(data); 283 | out['type'] = (parsed && parsed[1]) || ''; 284 | out['excludes'] = []; 285 | } 286 | return out; 287 | } 288 | 289 | function parsePluginsClosure(chunk, state) { 290 | return parseSpecialClosure(chunk, state, createStructureForPlugin); 291 | } 292 | 293 | function createStructureForPlugin(pluginRow) { 294 | var out = {}; 295 | 296 | var match; 297 | while(match = PLUGINS_LINE_PATTERN.exec(pluginRow)) { 298 | if (match && match[1]) { 299 | out[match[1]] = match[3]; 300 | } 301 | } 302 | 303 | return out; 304 | } 305 | 306 | function findFirstSpaceOrTabPosition(input) { 307 | var position = input.indexOf(' '); 308 | if (position === -1) { 309 | position = input.indexOf('\t'); 310 | } 311 | return position; 312 | } 313 | 314 | function findDependencyItemBlock(data) { 315 | var matches = DEPS_ITEM_BLOCK_REGEX.exec(data); 316 | if (matches && matches[2]) { 317 | var excludes = []; 318 | 319 | var match; 320 | while((match = DEPS_EXCLUDE_LINE_REGEX.exec(data))) { 321 | excludes.push(parseMapNotation(match[0].substring(findFirstSpaceOrTabPosition(match[0])))); 322 | } 323 | 324 | return { gav: matches[2], type: matches[1], excludes: excludes }; 325 | } 326 | return []; 327 | } 328 | 329 | function parseGavString(gavString) { 330 | var out = { group: '', name: '', version: '' }; 331 | var easyGavStringMatches = DEPS_EASY_GAV_STRING_REGEX.exec(gavString); 332 | if (easyGavStringMatches) { 333 | out['group'] = easyGavStringMatches[2]; 334 | out['name'] = easyGavStringMatches[3]; 335 | out['version'] = easyGavStringMatches[4]; 336 | } else if (gavString.indexOf('project(') !== -1) { 337 | out['name'] = gavString.match(/(project\([^\)]+\))/g)[0]; 338 | } else { 339 | var hardGavMatches = DEPS_HARD_GAV_STRING_REGEX.exec(gavString); 340 | if (hardGavMatches && (hardGavMatches[3] || hardGavMatches[2])) { 341 | out = parseMapNotationWithFallback(out, hardGavMatches[3] || hardGavMatches[2]); 342 | } else { 343 | out = parseMapNotationWithFallback(out, gavString, gavString.slice(findFirstSpaceOrTabPosition(gavString))); 344 | } 345 | } 346 | return out; 347 | } 348 | 349 | function parseMapNotationWithFallback(out, string, name) { 350 | var outFromMapNotation = parseMapNotation(string); 351 | if (outFromMapNotation['name']) { 352 | out = outFromMapNotation; 353 | } else { 354 | out['name'] = name ? name : string; 355 | } 356 | return out; 357 | } 358 | 359 | function parseMapNotation(input) { 360 | var out = {}; 361 | var currentKey = ''; 362 | var quotation = ''; 363 | 364 | for (var i = 0, max = input.length; i < max; i++) { 365 | if (input[i] === ':') { 366 | currentKey = currentKey.trim(); 367 | out[currentKey] = ''; 368 | 369 | for (var innerLoop = 0, i = i + 1; i < max; i++) { 370 | if (innerLoop === 0) { 371 | // Skip any leading spaces before the actual value 372 | if (isWhitespaceLiteral(input[i])) { 373 | continue; 374 | } 375 | } 376 | 377 | // We just take note of what the "latest" quote was so that we can 378 | if (input[i] === '"' || input[i] === "'") { 379 | quotation = input[i]; 380 | continue; 381 | } 382 | 383 | // Moving on to the next value if we find a comma 384 | if (input[i] === ',') { 385 | out[currentKey] = out[currentKey].trim(); 386 | currentKey = ''; 387 | break; 388 | } 389 | 390 | out[currentKey] += input[i]; 391 | innerLoop++; 392 | } 393 | } else { 394 | currentKey += input[i]; 395 | } 396 | } 397 | 398 | // If the last character contains a quotation mark, we remove it 399 | if (out[currentKey]) { 400 | out[currentKey] = out[currentKey].trim(); 401 | if (out[currentKey].slice(-1) === quotation) { 402 | out[currentKey] = out[currentKey].slice(0, -1); 403 | } 404 | } 405 | return out; 406 | } 407 | 408 | function parseRepositoryClosure(chunk, state) { 409 | var out = []; 410 | var repository = deepParse(chunk, state, true, false); 411 | Object.keys(repository).map(function(item) { 412 | if (repository[item]) { 413 | out.push({type: item, data: repository[item]}); 414 | } else { 415 | out.push({type: 'unknown', data: {name: item}}); 416 | } 417 | }); 418 | return out; 419 | } 420 | 421 | function parseSpecialClosure(chunk, state, mapFunction) { 422 | var out = []; 423 | // openBlockCount starts at 1 due to us entering after " {" 424 | var openBlockCount = 1; 425 | var currentKey = ''; 426 | var currentValue = ''; 427 | 428 | var isInItemBlock = false; 429 | for (; state.index < chunk.length; state.index++) { 430 | if (chunk[state.index] === CHAR_BLOCK_START) { 431 | openBlockCount++; 432 | } else if (chunk[state.index] === CHAR_BLOCK_END) { 433 | openBlockCount--; 434 | } else { 435 | currentKey += String.fromCharCode(chunk[state.index]); 436 | } 437 | 438 | // Keys shouldn't have any leading nor trailing whitespace 439 | currentKey = currentKey.trim(); 440 | 441 | if (isStartOfComment(currentKey)) { 442 | var commentText = currentKey; 443 | for (state.index = state.index + 1; state.index < chunk.length; state.index++) { 444 | if (isCommentComplete(commentText, chunk[state.index])) { 445 | currentKey = ''; 446 | break; 447 | } 448 | commentText += String.fromCharCode(chunk[state.index]); 449 | } 450 | } 451 | 452 | 453 | if (currentKey && isWhitespace(chunk[state.index])) { 454 | var character = ''; 455 | for (state.index = state.index + 1; state.index < chunk.length; state.index++) { 456 | character = chunk[state.index]; 457 | currentValue += String.fromCharCode(character); 458 | 459 | if (character === CHAR_BLOCK_START) { 460 | isInItemBlock = true; 461 | } else if (isInItemBlock && character === CHAR_BLOCK_END) { 462 | isInItemBlock = false; 463 | } else if (!isInItemBlock) { 464 | if (isLineBreakCharacter(character) && currentValue) { 465 | break; 466 | } 467 | } 468 | } 469 | 470 | out.push(mapFunction(currentKey + ' ' + currentValue)); 471 | currentKey = ''; 472 | currentValue = ''; 473 | } 474 | 475 | if (openBlockCount == 0) { 476 | break; 477 | } 478 | } 479 | return out; 480 | } 481 | 482 | function fetchDefinedNameOrSkipFunctionDefinition(chunk, state) { 483 | var character = 0; 484 | var temp = ''; 485 | var isVariableDefinition = true; 486 | for (var max = chunk.length; state.index < max; state.index++) { 487 | character = chunk[state.index]; 488 | 489 | if (character === CHAR_EQUALS) { 490 | // Variable definition, break and return name 491 | break; 492 | } else if (character === CHAR_LEFT_PARENTHESIS) { 493 | // Function definition, skip parsing 494 | isVariableDefinition = false; 495 | skipFunctionDefinition(chunk, state); 496 | break; 497 | } 498 | 499 | temp += String.fromCharCode(character); 500 | } 501 | 502 | if (isVariableDefinition) { 503 | var values = temp.trim().split(' '); 504 | return values[values.length - 1]; 505 | } else { 506 | return ''; 507 | } 508 | } 509 | 510 | function parseArray(chunk, state) { 511 | var character = 0; 512 | var temp = ''; 513 | for (var max = chunk.length; state.index < max; state.index++) { 514 | character = chunk[state.index]; 515 | if (character === CHAR_ARRAY_START) { 516 | continue; 517 | } else if (character === CHAR_ARRAY_END) { 518 | break; 519 | } 520 | temp += String.fromCharCode(character); 521 | } 522 | 523 | return temp.split(',').map(function(item) { 524 | return trimWrappingQuotes(item.trim()); 525 | }); 526 | } 527 | 528 | function skipFunctionCall(chunk, state) { 529 | var openParenthesisCount = 0; 530 | var character = ''; 531 | for (var max = chunk.length; state.index < max; state.index++) { 532 | character = chunk[state.index]; 533 | if (character === CHAR_LEFT_PARENTHESIS) { 534 | openParenthesisCount++; 535 | } else if (character === CHAR_RIGHT_PARENTHESIS) { 536 | openParenthesisCount--; 537 | } 538 | if (openParenthesisCount === 0 && !isWhitespace(character)) { 539 | state.index++; 540 | break; 541 | } 542 | } 543 | return openParenthesisCount === 0; 544 | } 545 | 546 | function addValueToStructure(structure, currentKey, value) { 547 | if (currentKey) { 548 | if (structure.hasOwnProperty(currentKey)) { 549 | if (structure[currentKey].constructor === Array) { 550 | structure[currentKey].push(getRealValue(value)); 551 | } else { 552 | var oldValue = structure[currentKey]; 553 | structure[currentKey] = [oldValue, getRealValue(value)]; 554 | } 555 | } else { 556 | structure[currentKey] = getRealValue(value); 557 | } 558 | } 559 | } 560 | 561 | function getRealValue(value) { 562 | if (value === 'true' || value === 'false') { // booleans 563 | return value === 'true'; 564 | } 565 | 566 | return value; 567 | } 568 | 569 | function trimWrappingQuotes(string) { 570 | var firstCharacter = string.slice(0, 1); 571 | if (firstCharacter === '"') { 572 | return string.replace(/^"([^"]+)"$/g, '$1'); 573 | } else if (firstCharacter === '\'') { 574 | return string.replace(/^'([^']+)'$/g, '$1'); 575 | } 576 | return string; 577 | } 578 | 579 | function isDelimiter(character) { 580 | return character === CHAR_SPACE || character === CHAR_EQUALS; 581 | } 582 | 583 | function isWhitespace(character) { 584 | return WHITESPACE_CHARACTERS.hasOwnProperty(character); 585 | } 586 | 587 | function isWhitespaceLiteral(character) { 588 | return isWhitespace(character.charCodeAt(0)); 589 | } 590 | 591 | function isLineBreakCharacter(character) { 592 | return character == CHAR_CARRIAGE_RETURN || character == CHAR_NEWLINE 593 | } 594 | 595 | function isKeyword(string) { 596 | return string === KEYWORD_DEF || string === KEYWORD_IF; 597 | } 598 | 599 | function isSingleLineComment(comment) { 600 | return comment.slice(0, 2) === SINGLE_LINE_COMMENT_START; 601 | } 602 | 603 | function isStartOfComment(snippet) { 604 | return snippet === BLOCK_COMMENT_START || snippet === SINGLE_LINE_COMMENT_START; 605 | } 606 | 607 | function isCommentComplete(text, next) { 608 | return (isLineBreakCharacter(next) && isSingleLineComment(text)) || (isWhitespace(next) && isEndOfMultiLineComment(text)); 609 | } 610 | 611 | function isEndOfMultiLineComment(comment) { 612 | return comment.slice(-2) === BLOCK_COMMENT_END; 613 | } 614 | 615 | function isFunctionCall(string) { 616 | return string.match(/\w+\(.*\);?$/) !== null; 617 | } 618 | 619 | function parse(readableStream) { 620 | return new Promise(function(resolve, reject) { 621 | var out = {}; 622 | readableStream.on('data', function(chunk) { 623 | var state = { 624 | index: 0, 625 | comment: { 626 | parsing: false, 627 | singleLine: false, 628 | multiLine: false, 629 | 630 | setSingleLine: function() { 631 | this._setCommentState(true, false); 632 | }, 633 | setMultiLine: function() { 634 | this._setCommentState(false, true); 635 | }, 636 | reset: function() { 637 | this._setCommentState(false, false); 638 | }, 639 | _setCommentState: function(singleLine, multiLine) { 640 | this.singleLine = singleLine; 641 | this.multiLine = multiLine; 642 | this.parsing = singleLine || multiLine; 643 | } 644 | } 645 | }; 646 | out = deepParse(chunk, state, false, undefined); 647 | }); 648 | 649 | readableStream.on('end', function() { 650 | resolve(out); 651 | }); 652 | readableStream.on('error', function(error) { 653 | reject('Error parsing stream: ' + error); 654 | }); 655 | }); 656 | } 657 | 658 | function parseText(text) { 659 | var textAsStream = new stream.Readable(); 660 | textAsStream._read = function noop() {}; 661 | textAsStream.push(text); 662 | textAsStream.push(null); 663 | return parse(textAsStream); 664 | } 665 | 666 | function parseFile(path) { 667 | var stream = fs.createReadStream(path); 668 | return parse(stream); 669 | } 670 | 671 | module.exports = { 672 | parseText: parseText, 673 | parseFile: parseFile 674 | }; 675 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | ansi-colors@3.2.3: 6 | version "3.2.3" 7 | resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" 8 | integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== 9 | 10 | ansi-regex@^3.0.0: 11 | version "3.0.1" 12 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" 13 | integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== 14 | 15 | ansi-regex@^4.1.0: 16 | version "4.1.0" 17 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" 18 | integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== 19 | 20 | ansi-styles@^3.2.0, ansi-styles@^3.2.1: 21 | version "3.2.1" 22 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 23 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 24 | dependencies: 25 | color-convert "^1.9.0" 26 | 27 | argparse@^1.0.7: 28 | version "1.0.10" 29 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" 30 | integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== 31 | dependencies: 32 | sprintf-js "~1.0.2" 33 | 34 | assertion-error@^1.1.0: 35 | version "1.1.0" 36 | resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" 37 | integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== 38 | 39 | balanced-match@^1.0.0: 40 | version "1.0.0" 41 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 42 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 43 | 44 | brace-expansion@^1.1.7: 45 | version "1.1.11" 46 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 47 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 48 | dependencies: 49 | balanced-match "^1.0.0" 50 | concat-map "0.0.1" 51 | 52 | browser-stdout@1.3.1: 53 | version "1.3.1" 54 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" 55 | integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== 56 | 57 | call-bind@^1.0.0, call-bind@^1.0.2: 58 | version "1.0.2" 59 | resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" 60 | integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== 61 | dependencies: 62 | function-bind "^1.1.1" 63 | get-intrinsic "^1.0.2" 64 | 65 | camelcase@^5.0.0: 66 | version "5.3.1" 67 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" 68 | integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== 69 | 70 | chai@^4.2.0: 71 | version "4.3.6" 72 | resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.6.tgz#ffe4ba2d9fa9d6680cc0b370adae709ec9011e9c" 73 | integrity sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q== 74 | dependencies: 75 | assertion-error "^1.1.0" 76 | check-error "^1.0.2" 77 | deep-eql "^3.0.1" 78 | get-func-name "^2.0.0" 79 | loupe "^2.3.1" 80 | pathval "^1.1.1" 81 | type-detect "^4.0.5" 82 | 83 | chalk@^2.0.1: 84 | version "2.4.2" 85 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 86 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 87 | dependencies: 88 | ansi-styles "^3.2.1" 89 | escape-string-regexp "^1.0.5" 90 | supports-color "^5.3.0" 91 | 92 | check-error@^1.0.2: 93 | version "1.0.2" 94 | resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" 95 | integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= 96 | 97 | cliui@^5.0.0: 98 | version "5.0.0" 99 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" 100 | integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== 101 | dependencies: 102 | string-width "^3.1.0" 103 | strip-ansi "^5.2.0" 104 | wrap-ansi "^5.1.0" 105 | 106 | color-convert@^1.9.0: 107 | version "1.9.3" 108 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 109 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 110 | dependencies: 111 | color-name "1.1.3" 112 | 113 | color-name@1.1.3: 114 | version "1.1.3" 115 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 116 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 117 | 118 | concat-map@0.0.1: 119 | version "0.0.1" 120 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 121 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 122 | 123 | debug@3.2.6: 124 | version "3.2.6" 125 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" 126 | integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== 127 | dependencies: 128 | ms "^2.1.1" 129 | 130 | decamelize@^1.2.0: 131 | version "1.2.0" 132 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" 133 | integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= 134 | 135 | deep-eql@^3.0.1: 136 | version "3.0.1" 137 | resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" 138 | integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== 139 | dependencies: 140 | type-detect "^4.0.0" 141 | 142 | define-properties@^1.1.2, define-properties@^1.1.3: 143 | version "1.1.3" 144 | resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" 145 | integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== 146 | dependencies: 147 | object-keys "^1.0.12" 148 | 149 | diff@3.5.0: 150 | version "3.5.0" 151 | resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" 152 | integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== 153 | 154 | emoji-regex@^7.0.1: 155 | version "7.0.3" 156 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" 157 | integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== 158 | 159 | es-abstract@^1.18.0-next.2: 160 | version "1.18.0-next.2" 161 | resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.2.tgz#088101a55f0541f595e7e057199e27ddc8f3a5c2" 162 | integrity sha512-Ih4ZMFHEtZupnUh6497zEL4y2+w8+1ljnCyaTa+adcoafI1GOvMwFlDjBLfWR7y9VLfrjRJe9ocuHY1PSR9jjw== 163 | dependencies: 164 | call-bind "^1.0.2" 165 | es-to-primitive "^1.2.1" 166 | function-bind "^1.1.1" 167 | get-intrinsic "^1.0.2" 168 | has "^1.0.3" 169 | has-symbols "^1.0.1" 170 | is-callable "^1.2.2" 171 | is-negative-zero "^2.0.1" 172 | is-regex "^1.1.1" 173 | object-inspect "^1.9.0" 174 | object-keys "^1.1.1" 175 | object.assign "^4.1.2" 176 | string.prototype.trimend "^1.0.3" 177 | string.prototype.trimstart "^1.0.3" 178 | 179 | es-to-primitive@^1.2.1: 180 | version "1.2.1" 181 | resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" 182 | integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== 183 | dependencies: 184 | is-callable "^1.1.4" 185 | is-date-object "^1.0.1" 186 | is-symbol "^1.0.2" 187 | 188 | escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5: 189 | version "1.0.5" 190 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 191 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 192 | 193 | esprima@^4.0.0: 194 | version "4.0.1" 195 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" 196 | integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== 197 | 198 | find-up@3.0.0, find-up@^3.0.0: 199 | version "3.0.0" 200 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" 201 | integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== 202 | dependencies: 203 | locate-path "^3.0.0" 204 | 205 | flat@^4.1.0: 206 | version "4.1.1" 207 | resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.1.tgz#a392059cc382881ff98642f5da4dde0a959f309b" 208 | integrity sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA== 209 | dependencies: 210 | is-buffer "~2.0.3" 211 | 212 | fs.realpath@^1.0.0: 213 | version "1.0.0" 214 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 215 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 216 | 217 | function-bind@^1.1.1: 218 | version "1.1.1" 219 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 220 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 221 | 222 | get-caller-file@^2.0.1: 223 | version "2.0.5" 224 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" 225 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== 226 | 227 | get-func-name@^2.0.0: 228 | version "2.0.0" 229 | resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" 230 | integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= 231 | 232 | get-intrinsic@^1.0.2: 233 | version "1.1.1" 234 | resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" 235 | integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== 236 | dependencies: 237 | function-bind "^1.1.1" 238 | has "^1.0.3" 239 | has-symbols "^1.0.1" 240 | 241 | glob@7.1.3: 242 | version "7.1.3" 243 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" 244 | integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== 245 | dependencies: 246 | fs.realpath "^1.0.0" 247 | inflight "^1.0.4" 248 | inherits "2" 249 | minimatch "^3.0.4" 250 | once "^1.3.0" 251 | path-is-absolute "^1.0.0" 252 | 253 | growl@1.10.5: 254 | version "1.10.5" 255 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" 256 | integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== 257 | 258 | has-flag@^3.0.0: 259 | version "3.0.0" 260 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 261 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 262 | 263 | has-symbols@^1.0.0, has-symbols@^1.0.1: 264 | version "1.0.1" 265 | resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" 266 | integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== 267 | 268 | has@^1.0.3: 269 | version "1.0.3" 270 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 271 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 272 | dependencies: 273 | function-bind "^1.1.1" 274 | 275 | he@1.2.0: 276 | version "1.2.0" 277 | resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" 278 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== 279 | 280 | inflight@^1.0.4: 281 | version "1.0.6" 282 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 283 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 284 | dependencies: 285 | once "^1.3.0" 286 | wrappy "1" 287 | 288 | inherits@2: 289 | version "2.0.4" 290 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 291 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 292 | 293 | is-buffer@~2.0.3: 294 | version "2.0.5" 295 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" 296 | integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== 297 | 298 | is-callable@^1.1.4, is-callable@^1.2.2: 299 | version "1.2.3" 300 | resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e" 301 | integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ== 302 | 303 | is-date-object@^1.0.1: 304 | version "1.0.2" 305 | resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" 306 | integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== 307 | 308 | is-fullwidth-code-point@^2.0.0: 309 | version "2.0.0" 310 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" 311 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= 312 | 313 | is-negative-zero@^2.0.1: 314 | version "2.0.1" 315 | resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" 316 | integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== 317 | 318 | is-regex@^1.1.1: 319 | version "1.1.2" 320 | resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.2.tgz#81c8ebde4db142f2cf1c53fc86d6a45788266251" 321 | integrity sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg== 322 | dependencies: 323 | call-bind "^1.0.2" 324 | has-symbols "^1.0.1" 325 | 326 | is-symbol@^1.0.2: 327 | version "1.0.3" 328 | resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" 329 | integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== 330 | dependencies: 331 | has-symbols "^1.0.1" 332 | 333 | isexe@^2.0.0: 334 | version "2.0.0" 335 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 336 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= 337 | 338 | js-yaml@3.13.1: 339 | version "3.13.1" 340 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" 341 | integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== 342 | dependencies: 343 | argparse "^1.0.7" 344 | esprima "^4.0.0" 345 | 346 | locate-path@^3.0.0: 347 | version "3.0.0" 348 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" 349 | integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== 350 | dependencies: 351 | p-locate "^3.0.0" 352 | path-exists "^3.0.0" 353 | 354 | lodash.merge@^4.6.2: 355 | version "4.6.2" 356 | resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" 357 | integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== 358 | 359 | lodash@^4.17.15: 360 | version "4.17.21" 361 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" 362 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 363 | 364 | log-symbols@2.2.0: 365 | version "2.2.0" 366 | resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" 367 | integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== 368 | dependencies: 369 | chalk "^2.0.1" 370 | 371 | loupe@^2.3.1: 372 | version "2.3.2" 373 | resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.2.tgz#799a566ba5aa8d11b93ddccc92c569bbae7e9490" 374 | integrity sha512-QgVamnvj0jX1LMPlCAq0MK6hATORFtGqHoUKXTkwNe13BqlN6aePQCKnnTcFvdDYEEITcJ+gBl4mTW7YJtJbyQ== 375 | dependencies: 376 | get-func-name "^2.0.0" 377 | 378 | minimatch@3.0.4, minimatch@^3.0.4: 379 | version "3.0.4" 380 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 381 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 382 | dependencies: 383 | brace-expansion "^1.1.7" 384 | 385 | minimist@^1.2.5: 386 | version "1.2.6" 387 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" 388 | integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== 389 | 390 | mkdirp@0.5.4: 391 | version "0.5.4" 392 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.4.tgz#fd01504a6797ec5c9be81ff43d204961ed64a512" 393 | integrity sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw== 394 | dependencies: 395 | minimist "^1.2.5" 396 | 397 | mocha@^6.2.0: 398 | version "6.2.3" 399 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.2.3.tgz#e648432181d8b99393410212664450a4c1e31912" 400 | integrity sha512-0R/3FvjIGH3eEuG17ccFPk117XL2rWxatr81a57D+r/x2uTYZRbdZ4oVidEUMh2W2TJDa7MdAb12Lm2/qrKajg== 401 | dependencies: 402 | ansi-colors "3.2.3" 403 | browser-stdout "1.3.1" 404 | debug "3.2.6" 405 | diff "3.5.0" 406 | escape-string-regexp "1.0.5" 407 | find-up "3.0.0" 408 | glob "7.1.3" 409 | growl "1.10.5" 410 | he "1.2.0" 411 | js-yaml "3.13.1" 412 | log-symbols "2.2.0" 413 | minimatch "3.0.4" 414 | mkdirp "0.5.4" 415 | ms "2.1.1" 416 | node-environment-flags "1.0.5" 417 | object.assign "4.1.0" 418 | strip-json-comments "2.0.1" 419 | supports-color "6.0.0" 420 | which "1.3.1" 421 | wide-align "1.1.3" 422 | yargs "13.3.2" 423 | yargs-parser "13.1.2" 424 | yargs-unparser "1.6.0" 425 | 426 | ms@2.1.1: 427 | version "2.1.1" 428 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" 429 | integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== 430 | 431 | ms@^2.1.1: 432 | version "2.1.3" 433 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" 434 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== 435 | 436 | multiline@^2.0.0: 437 | version "2.0.0" 438 | resolved "https://registry.yarnpkg.com/multiline/-/multiline-2.0.0.tgz#4bb44ddc474c4fa6deaee4266c75c7be2535127a" 439 | integrity sha512-+HpXaUcV8PIGNNmuhtlaVmw4NH0W30/A5WP+rq6pxZYBjDslX/sXkFgL3Mgk1cSGGIICjWu4gNStkJXL6ZM2DQ== 440 | dependencies: 441 | strip-indent "^2.0.0" 442 | 443 | node-environment-flags@1.0.5: 444 | version "1.0.5" 445 | resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a" 446 | integrity sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ== 447 | dependencies: 448 | object.getownpropertydescriptors "^2.0.3" 449 | semver "^5.7.0" 450 | 451 | object-inspect@^1.9.0: 452 | version "1.9.0" 453 | resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a" 454 | integrity sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw== 455 | 456 | object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: 457 | version "1.1.1" 458 | resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" 459 | integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== 460 | 461 | object.assign@4.1.0: 462 | version "4.1.0" 463 | resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" 464 | integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== 465 | dependencies: 466 | define-properties "^1.1.2" 467 | function-bind "^1.1.1" 468 | has-symbols "^1.0.0" 469 | object-keys "^1.0.11" 470 | 471 | object.assign@^4.1.2: 472 | version "4.1.2" 473 | resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" 474 | integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== 475 | dependencies: 476 | call-bind "^1.0.0" 477 | define-properties "^1.1.3" 478 | has-symbols "^1.0.1" 479 | object-keys "^1.1.1" 480 | 481 | object.getownpropertydescriptors@^2.0.3: 482 | version "2.1.2" 483 | resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz#1bd63aeacf0d5d2d2f31b5e393b03a7c601a23f7" 484 | integrity sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ== 485 | dependencies: 486 | call-bind "^1.0.2" 487 | define-properties "^1.1.3" 488 | es-abstract "^1.18.0-next.2" 489 | 490 | once@^1.3.0: 491 | version "1.4.0" 492 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 493 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 494 | dependencies: 495 | wrappy "1" 496 | 497 | p-limit@^2.0.0: 498 | version "2.3.0" 499 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" 500 | integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== 501 | dependencies: 502 | p-try "^2.0.0" 503 | 504 | p-locate@^3.0.0: 505 | version "3.0.0" 506 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" 507 | integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== 508 | dependencies: 509 | p-limit "^2.0.0" 510 | 511 | p-try@^2.0.0: 512 | version "2.2.0" 513 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" 514 | integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== 515 | 516 | path-exists@^3.0.0: 517 | version "3.0.0" 518 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" 519 | integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= 520 | 521 | path-is-absolute@^1.0.0: 522 | version "1.0.1" 523 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 524 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 525 | 526 | pathval@^1.1.1: 527 | version "1.1.1" 528 | resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" 529 | integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== 530 | 531 | require-directory@^2.1.1: 532 | version "2.1.1" 533 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" 534 | integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= 535 | 536 | require-main-filename@^2.0.0: 537 | version "2.0.0" 538 | resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" 539 | integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== 540 | 541 | semver@^5.7.0: 542 | version "5.7.2" 543 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" 544 | integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== 545 | 546 | set-blocking@^2.0.0: 547 | version "2.0.0" 548 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 549 | integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= 550 | 551 | sprintf-js@~1.0.2: 552 | version "1.0.3" 553 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 554 | integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= 555 | 556 | "string-width@^1.0.2 || 2": 557 | version "2.1.1" 558 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" 559 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== 560 | dependencies: 561 | is-fullwidth-code-point "^2.0.0" 562 | strip-ansi "^4.0.0" 563 | 564 | string-width@^3.0.0, string-width@^3.1.0: 565 | version "3.1.0" 566 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" 567 | integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== 568 | dependencies: 569 | emoji-regex "^7.0.1" 570 | is-fullwidth-code-point "^2.0.0" 571 | strip-ansi "^5.1.0" 572 | 573 | string.prototype.trimend@^1.0.3: 574 | version "1.0.4" 575 | resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" 576 | integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== 577 | dependencies: 578 | call-bind "^1.0.2" 579 | define-properties "^1.1.3" 580 | 581 | string.prototype.trimstart@^1.0.3: 582 | version "1.0.4" 583 | resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" 584 | integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== 585 | dependencies: 586 | call-bind "^1.0.2" 587 | define-properties "^1.1.3" 588 | 589 | strip-ansi@^4.0.0: 590 | version "4.0.0" 591 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" 592 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= 593 | dependencies: 594 | ansi-regex "^3.0.0" 595 | 596 | strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: 597 | version "5.2.0" 598 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" 599 | integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== 600 | dependencies: 601 | ansi-regex "^4.1.0" 602 | 603 | strip-indent@^2.0.0: 604 | version "2.0.0" 605 | resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" 606 | integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g= 607 | 608 | strip-json-comments@2.0.1: 609 | version "2.0.1" 610 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 611 | integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= 612 | 613 | supports-color@6.0.0: 614 | version "6.0.0" 615 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" 616 | integrity sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg== 617 | dependencies: 618 | has-flag "^3.0.0" 619 | 620 | supports-color@^5.3.0: 621 | version "5.5.0" 622 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 623 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 624 | dependencies: 625 | has-flag "^3.0.0" 626 | 627 | type-detect@^4.0.0, type-detect@^4.0.5: 628 | version "4.0.8" 629 | resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" 630 | integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== 631 | 632 | which-module@^2.0.0: 633 | version "2.0.0" 634 | resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" 635 | integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= 636 | 637 | which@1.3.1: 638 | version "1.3.1" 639 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" 640 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== 641 | dependencies: 642 | isexe "^2.0.0" 643 | 644 | wide-align@1.1.3: 645 | version "1.1.3" 646 | resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" 647 | integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== 648 | dependencies: 649 | string-width "^1.0.2 || 2" 650 | 651 | wrap-ansi@^5.1.0: 652 | version "5.1.0" 653 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" 654 | integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== 655 | dependencies: 656 | ansi-styles "^3.2.0" 657 | string-width "^3.0.0" 658 | strip-ansi "^5.0.0" 659 | 660 | wrappy@1: 661 | version "1.0.2" 662 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 663 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 664 | 665 | y18n@^4.0.0: 666 | version "4.0.1" 667 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.1.tgz#8db2b83c31c5d75099bb890b23f3094891e247d4" 668 | integrity sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ== 669 | 670 | yargs-parser@13.1.2, yargs-parser@^13.1.2: 671 | version "13.1.2" 672 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" 673 | integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== 674 | dependencies: 675 | camelcase "^5.0.0" 676 | decamelize "^1.2.0" 677 | 678 | yargs-unparser@1.6.0: 679 | version "1.6.0" 680 | resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" 681 | integrity sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw== 682 | dependencies: 683 | flat "^4.1.0" 684 | lodash "^4.17.15" 685 | yargs "^13.3.0" 686 | 687 | yargs@13.3.2, yargs@^13.3.0: 688 | version "13.3.2" 689 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" 690 | integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== 691 | dependencies: 692 | cliui "^5.0.0" 693 | find-up "^3.0.0" 694 | get-caller-file "^2.0.1" 695 | require-directory "^2.1.1" 696 | require-main-filename "^2.0.0" 697 | set-blocking "^2.0.0" 698 | string-width "^3.0.0" 699 | which-module "^2.0.0" 700 | y18n "^4.0.0" 701 | yargs-parser "^13.1.2" 702 | --------------------------------------------------------------------------------