diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b80db07..34a9266 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,26 +1,25 @@ -name: CI +name: CI Tests -on: [push] - -env: - CI: true +on: + - push + - pull_request jobs: - Test: + test: + name: Test strategy: matrix: - os: [ubuntu-latest, macos-latest, windows-latest] + os: [ubuntu-20.04, macos-latest, windows-2019] + fail-fast: false runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v1 - - uses: actions/setup-node@v2 - with: - node-version: '14' - - name: Install windows-build-tools - if: ${{ matrix.os == 'windows-latest' }} - run: | - npm config set msvs_version 2019 - - name: Install dependencies - run: npm i - - name: Run tests - run: npm test + - name: Checkout our Source + uses: actions/checkout@v3 + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 16 + - name: Install Dependencies + run: npm install + - name: Run Tests + run: npm test diff --git a/.gitignore b/.gitignore index b84d4db..a9d1858 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ node_modules/ .DS_Store npm-debug.log -lib/ api.json diff --git a/Gruntfile.coffee b/Gruntfile.coffee deleted file mode 100644 index e8fb1bd..0000000 --- a/Gruntfile.coffee +++ /dev/null @@ -1,61 +0,0 @@ -module.exports = (grunt) -> - grunt.initConfig - pkg: grunt.file.readJSON('package.json') - - coffee: - glob_to_multiple: - expand: true - cwd: 'src' - src: ['*.coffee'] - dest: 'lib' - ext: '.js' - - coffeelint: - options: - no_empty_param_list: - level: 'error' - max_line_length: - level: 'ignore' - - src: ['src/*.coffee'] - test: ['spec/*.coffee'] - gruntfile: ['Gruntfile.coffee'] - benchmark: ['benchmark/*.coffee'] - - peg: - glob_to_multiple: - expand: true - cwd: 'src' - src: ['*.pegjs'] - dest: 'lib' - ext: '.js' - - shell: - test: - command: 'node node_modules/jasmine-focused/bin/jasmine-focused --coffee --captureExceptions spec' - options: - stdout: true - stderr: true - failOnError: true - - 'update-atomdoc': - command: 'npm update grunt-atomdoc' - options: - stdout: true - stderr: true - failOnError: true - - grunt.loadNpmTasks('grunt-contrib-coffee') - grunt.loadNpmTasks('grunt-shell') - grunt.loadNpmTasks('grunt-coffeelint') - grunt.loadNpmTasks('grunt-peg') - grunt.loadNpmTasks('grunt-atomdoc') - - grunt.registerTask 'clean', -> - require('rimraf').sync('lib') - require('rimraf').sync('api.json') - - grunt.registerTask('lint', ['coffeelint']) - grunt.registerTask('default', ['coffee', 'peg', 'lint']) - grunt.registerTask('prepublish', ['clean', 'coffee', 'peg', 'lint', 'shell:update-atomdoc', 'atomdoc']) - grunt.registerTask('test', ['default', 'shell:test']) diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..1b2e9bb --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,8 @@ +module.exports = (grunt) => { + grunt.initConfig({ + pkg: grunt.file.readJSON("package.json") + + }); + + grunt.loadNpmTasks("grunt-atomdoc"); +}; diff --git a/README.md b/README.md index 0f331f9..b2a8187 100644 --- a/README.md +++ b/README.md @@ -120,3 +120,4 @@ lines and a `tags` key, pointing to an array of tags arrays described above. * Run `npm test` to run the specs * Run `npm run benchmark` to benchmark fully tokenizing jQuery 2.0.3 and the CSS for Twitter Bootstrap 3.1.1 + * If you make changes to `./src/scope-selector-parser.pegjs` ensure to run `npm run parse` to generate the JS form of PegJS. diff --git a/lib/first-mate.js b/lib/first-mate.js new file mode 100644 index 0000000..4db9737 --- /dev/null +++ b/lib/first-mate.js @@ -0,0 +1,9 @@ + +module.exports = { + ScopeSelector: require("./scope-selector.js"), + GrammarRegistry: require("./grammar-registry.js"), + Grammar: require("./grammar.js"), + get OnigRegExp() { + return require("oniguruma").OnigRegExp; + } +}; diff --git a/lib/grammar-registry.js b/lib/grammar-registry.js new file mode 100644 index 0000000..13629e2 --- /dev/null +++ b/lib/grammar-registry.js @@ -0,0 +1,322 @@ +const _ = require("underscore-plus"); +const CSON = require("season"); +const Grim = require("grim"); +const { Emitter, Disposable } = require("event-kit"); +const Grammar = require("./grammar.js"); +const NullGrammar = require("./null-grammar.js"); + +// Extended: Registry containing one or more grammars. +class GrammarRegistry { + constructor(options) { + if (options == null) { + options = {}; + } + this.maxTokensPerLine = options.maxTokensPerLine != null ? options.maxTokensPerLine : Infinity; + this.maxLineLength = options.maxLineLength != null ? options.maxLineLength : Infinity; + this.nullGrammar = new NullGrammar(this); + this.clear(); + } + + clear() { + this.emitter = new Emitter; + this.grammars = []; + this.grammarsByScopeName = {}; + this.injectionGrammars = []; + this.grammarOverridesByPath = {}; + this.scopeIdCounter = -1; + this.idsByScope = {}; + this.scopesById = {}; + return this.addGrammar(this.nullGrammar); + } + + // ### + // Section: Event Subscription + // ### + + // Public: Invoke the given callback when a grammar is added to the registry. + // + // * `callback` {Function} to call when a grammar is added. + // * `grammar` {Grammar} that was added. + // + // Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. + onDidAddGrammar(callback) { + return this.emitter.on('did-add-grammar', callback); + } + + // Public: Invoke the given callback when a grammar is updated due to a grammar + // it depends on being added or removed from the registry. + // + // * `callback` {Function} to call when a grammar is updated. + // * `grammar` {Grammar} that was updated. + // + // Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. + onDidUpdateGrammar(callback) { + return this.emitter.on('did-update-grammar', callback); + } + + // Public: Invoke the given callback when a grammar is removed from the registry. + // + // * `callback` {Function} to call when a grammar is removed. + // * `grammar` {Grammar} that was removed. + // + // Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. + onDidRemoveGrammar(callback) { + return this.emitter.on('did-remove-grammar', callback); + } + + // ### + // Section: Managing Grammars + // ### + + // Public: Get all the grammars in this registry. + // + // Returns a non-empty {Array} of {Grammar} instances. + getGrammars() { + return _.clone(this.grammars); + } + + // Public: Get a grammar with the given scope name. + // + // * `scopeName` A {String} such as `"source.js"`. + // + // Returns a {Grammar} or undefined. + grammarForScopeName(scopeName) { + return this.grammarsByScopeName[scopeName]; + } + + // Public: Add a grammar to this registry. + // + // A 'grammar-added' event is emitted after the grammar is added. + // + // * `grammar` The {Grammar} to add. This should be a value previously returned + // from {::readGrammar} or {::readGrammarSync}. + // + // Returns a {Disposable} on which `.dispose()` can be called to remove the + // grammar. + addGrammar(grammar) { + this.grammars.push(grammar); + this.grammarsByScopeName[grammar.scopeName] = grammar; + if (grammar.injectionSelector != null) { + this.injectionGrammars.push(grammar); + } + this.grammarUpdated(grammar.scopeName); + if (Grammar.includeDeprecatedAPIs) { + this.emit('grammar-added', grammar); + } + this.emitter.emit('did-add-grammar', grammar); + return new Disposable(() => { + this.removeGrammar(grammar); + }); + } + + removeGrammar(grammar) { + _.remove(this.grammars, grammar); + delete this.grammarsByScopeName[grammar.scopeName]; + _.remove(this.injectionGrammars, grammar); + this.grammarUpdated(grammar.scopeName); + this.emitter.emit('did-remove-grammar', grammar); + return void 0; + } + + // Public: Remove the grammar with the given scope name. + // + // * `scopeName` A {String} such as `"source.js"`. + // + // Returns the removed {Grammar} or undefined. + removeGrammarForScopeName(scopeName) { + let grammar = this.grammarForScopeName(scopeName); + if (grammar != null) { + this.removeGrammar(grammar); + } + return grammar; + } + + // Public: Read a grammar synchronously but don't add it to the registry. + // + // * `grammarPath` A {String} absolute file path to a grammar file. + // + // Returns a {Grammar}. + readGrammarSync(grammarPath) { + // Adding `grammarFile` to avoid reading from disk twice + let grammarFile = CSON.readFileSync(grammarPath); + let grammar = grammarFile != null ? grammarFile : {}; + if (typeof grammar.scopeName === 'string' && grammar.scopeName.length > 0) { + return this.createGrammar(grammarPath, grammar); + } else { + throw new Error(`Grammar missing required scopeName property: ${grammarPath}`); + } + } + + // Public: Read a grammar asynchronously but don't add it to the registry. + // + // * `grammarPath` A {String} absolute file path to a grammar file. + // * `callback` A {Function} to call when read with the following arguments: + // * `error` An {Error}, may be null. + // * `grammar` A {Grammar} or null if an error occured. + // + // Returns undefined. + readGrammar(grammarPath, callback) { + CSON.readFile(grammarPath, ((_this) => { + return function(error, grammar) { + if (grammar == null) { + grammar = {}; + } + if (error != null) { + return typeof callback === "function" ? callback(error) : void 0; + } else { + if (typeof grammar.scopeName === 'string' && grammar.scopeName.length > 0) { + return typeof callback === "function" ? callback(null, _this.createGrammar(grammarPath, grammar)) : void 0; + } else { + return typeof callback === "function" ? callback(new Error(`Grammar missing required scopeName property: ${grammarPath}`)) : void 0; + } + } + } + })(this)); + return void 0; + } + + // Public: Read a grammar synchronously and add it to this registry. + // + // * `grammarPath` A {String} absolute file path to a grammar file. + // + // Returns a {Grammar}. + loadGrammarSync(grammarPath) { + let grammar = this.readGrammarSync(grammarPath); + this.addGrammar(grammar); + return grammar; + } + + // Public: Read a grammar asynchronously and add it to the registry. + // + // * `grammarPath` A {String} absolute file path to a grammar file. + // * `callback` A {Function} to call when loaded with the following arguments: + // * `error` An {Error}, may be null. + // * `grammar` A {Grammar} or null if an error occured. + // + // Returns undefined. + loadGrammar(grammarPath, callback) { + this.readGrammar(grammarPath, ((_this) => { + return function(error, grammar) { + if (error != null) { + return typeof callback === "function" ? callback(error) : void 0; + } else { + _this.addGrammar(grammar); + return typeof callback === "function" ? callback(null, grammar) : void 0; + } + }; + })(this)); + return void 0; + } + + startIdForScope(scope) { + let id; + if (!(id = this.idsByScope[scope])) { + id = this.scopeIdCounter; + this.scopeIdCounter -= 2; + this.idsByScope[scope] = id; + this.scopesById[id] = scope; + } + return id; + } + + endIdForScope(scope) { + return this.startIdForScope(scope) - 1; + } + + scopeForId(id) { + if ((id % 2) === -1) { + return this.scopesById[id]; // start id + } else { + return this.scopesById[id + 1]; // end id + } + } + + grammarUpdated(scopeName) { + for (let i = 0; i < this.grammars.length; i++) { + if (this.grammars[i].scopeName !== scopeName) { + if (this.grammars[i].grammarUpdated(scopeName)) { + if (Grammar.includeDeprecatedAPIs) { + this.emit("grammar-updated", grammar); + } + this.emitter.emit("did-update-grammar"); + } + } + } + } + + createGrammar(grammarPath, object) { + if (object.maxTokensPerLine == null) { + object.maxTokensPerLine = this.maxTokensPerLine; + } + if (object.maxLineLength == null) { + object.maxLineLength = this.maxLineLength; + } + if (object.limitLineLength === false) { + object.maxLineLength = Infinity; + } + let grammar = new Grammar(this, object); + grammar.path = grammarPath; + return grammar; + } + + decodeTokens(lineText, tags, scopeTags, fn) { + if (scopeTags == null) { + scopeTags = []; + } + let offset = 0; + let scopeNames = scopeTags.map(((_this) => { + return function(tag) { + return _this.scopeForId(tag); + }; + })(this)); + let tokens = []; + for (let i = 0; i < tags.length; ++i) { + // positive numbers indicate string content with length equaling the number. + let tag = tags[i]; + if (tag >= 0) { + let token = { + value: lineText.substring(offset, offset + tag), + scopes: scopeNames.slice() + }; + if (fn != null) { + token = fn(token, index); + } + tokens.push(token); + offset += tag; + // odd negative numbers are being scope tags + } else if ((tag % 2) === -1) { + scopeTags.push(tag); + scopeNames.push(this.scopeForId(tag)); + // even negative numbers are end scope tags + } else { + scopeTags.pop(); + let expectedScopeName = this.scopeForId(tag + 1); + let poppedScopeName = scopeNames.pop(); + if (poppedScopeName !== expectedScopeName) { + throw new Error(`Expected popped scope to be ${expectedScopeName}, but it was ${poppedScopeName}`); + } + } + } + return tokens; + } +} + +if (Grim.includeDeprecatedAPIs) { + EmitterMixin = require('emissary').Emitter; + EmitterMixin.includeInto(GrammarRegistry); + GrammarRegistry.prototype.on = function(eventName) { + switch (eventName) { + case 'grammar-added': + Grim.deprecate("Call GrammarRegistry::onDidAddGrammar instead"); + break; + case 'grammar-updated': + Grim.deprecate("Call GrammarRegistry::onDidUpdateGrammar instead"); + break; + default: + Grim.deprecate("Call explicit event subscription methods instead"); + } + return EmitterMixin.prototype.on.apply(this, arguments); + }; +} + +module.exports = GrammarRegistry; diff --git a/lib/grammar.js b/lib/grammar.js new file mode 100644 index 0000000..1916ebe --- /dev/null +++ b/lib/grammar.js @@ -0,0 +1,438 @@ +const path = require("path"); +const _ = require("underscore-plus"); +const fs = require("fs-plus"); +const {OnigRegExp, OnigString} = require("oniguruma"); +const {Emitter} = require("event-kit"); +const Grim = require("grim"); +const Injections = require("./injections.js"); +const Pattern = require("./pattern.js"); +const Rule = require("./rule.js"); +const ScopeSelector = require("./scope-selector.js"); + +// Extended: Grammar that tokenizes lines of text. +// +// This class should not be instantiated directly but instead obtained from +// a {GrammarRegistry} by calling {GrammarRegistry::loadGrammar}. +class Grammar { + constructor(registry, options) { + this.registry = registry; + if (options == null) { + options = {}; + } + this.name = options.name; + this.fileTypes = options.fileTypes; + this.scopeName = options.scopeName; + this.foldingStopMarker = options.folderingStopMarker; + this.maxTokensPerLine = options.maxTokensPerLine; + this.maxLineLength = options.maxLineLength; + + let injections = options.injections; + let injectionSelector = options.injectionSelector; + let patterns = options.patterns; + let repository = options.repository; + let firstLineMatch = options.firstLineMatch; + let contentRegex = options.contentRegex; + + this.emitter = new Emitter; + this.repository = null; + this.initialRule = null; + + if (injectionSelector != null) { + this.injectionSelector = new ScopeSelector(injectionSelector); + } else { + this.injectionSelector = null; + } + if (firstLineMatch) { + this.firstLineRegex = new OnigRegExp(firstLineMatch); + } else { + this.firstLineRegex = null; + } + if (contentRegex) { + this.contentRegex = new OnigRegExp(contentRegex); + } else { + this.contentRegex = null; + } + if (this.fileTypes == null) { + this.fileTypes = []; + } + + this.includedGrammarScopes = []; + this.rawPatterns = patterns; + this.rawRepository = repository; + this.rawInjections = injections; + this.updateRules(); + } + + // ### + // Section: Event Subscription + // ### + + // Public: Invoke the given callback when this grammar is updated due to a + // grammar it depends on being added or removed from the registry. + // + // * `callback` {Function} to call when this grammar is updated. + // + // Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. + onDidUpdate(callback) { + return this.emitter.on('did-update', callback); + } + + // ### + // Section: Tokenizing + // ### + + // Public: Tokenize all lines in the given text. + // + // * `text` A {String} containing one or more lines. + // + // Returns an {Array} of token arrays for each line tokenizied. + tokenizeLines(text, compatibilityMode) { + if (compatibilityMode == null) { + compatibilityMode = true; + } + let lines = text.split('\n'); + let lastLine = lines.length - 1; + let ruleStack = null; + let scopes = []; + let _results = []; + for (let i = 0; i < lines.length; ++i) { + let line = lines[i]; + let _ref1 = this.tokenizeLine(line, ruleStack, i === 0, compatibilityMode, i !== lastLine); + let tags = _ref1.tags; + ruleStack = _ref1.ruleStack; + _results.push(this.registry.decodeTokens(line, tags, scopes)); + } + return _results; + } + + //Public: Tokenize the line of text. + // + //* `line` A {String} of text to tokenize. + //* `ruleStack` An optional {Array} of rules previously returned from this + // method. This should be null when tokenizing the first line in the file. + //* `firstLine` A optional {Boolean} denoting whether this is the first line + // in the file which defaults to `false`. This should be `true` + // when tokenizing the first line in the file. + // + //Returns an {Object} containing the following properties: + //* `line` The {String} of text that was tokenized. + //* `tags` An {Array} of integer scope ids and strings. Positive ids + // indicate the beginning of a scope, and negative tags indicate the end. + // To resolve ids to scope names, call {GrammarRegistry::scopeForId} with the + // absolute value of the id. + //* `tokens` This is a dynamic property. Invoking it will incur additional + // overhead, but will automatically translate the `tags` into token objects + // with `value` and `scopes` properties. + //* `ruleStack` An {Array} of rules representing the tokenized state at the + // end of the line. These should be passed back into this method when + // tokenizing the next line in the file. + tokenizeLine(inputLine, ruleStack, firstLine, compatibilityMode, appendNewLine) { // todo + let line, openScopeTags; + if (firstLine == null) { + firstLine = false; + } + if (compatibilityMode == null) { + compatibilityMode = true; + } + if (appendNewLine == null) { + appendNewLine = true; + } + let tags = []; + let truncatedLine = false; + if (inputLine.length > this.maxLineLength) { + line = inputLine.slice(0, this.maxLineLength); + truncatedLine = true; + } else { + line = inputLine; + } + let string = new OnigString(line); + let stringWithNewLine = appendNewLine ? new OnigString(line + '\n') : string; + if (ruleStack != null) { + ruleStack = ruleStack.slice(); + if (compatibilityMode) { + openScopeTags = []; + for (let i = 0; i < ruleStack.length; i++) { + if (ruleStack[i].scopeName) { + openScopeTags.push(this.registry.startIdForScope(ruleStack[i].scopeName)); + } + if (ruleStack[i].contentScopeName) { + openScopeTags.push(this.registry.startIdForScope(ruleStack[i].contentScopeName)); + } + } + } + } else { + if (compatibilityMode) { + openScopeTags = []; + } + ruleStack = [ + { + rule: this.initialRule, + scopeName: this.initialRule.scopeName, + contentScopeName: this.initialRule.contentScopeName + } + ]; + if (this.initialRule.scopeName) { + tags.push(this.startIdForScope(this.initialRule.scopeName)); + } + if (this.initialRule.contentScopeName) { + tags.push(this.startIdForScope(this.initialRule.contentScopeName)); + } + } + let initialRuleStackLength = ruleStack.length; + let position = 0; + let tokenCount = 0; + while (true) { + let previousRuleStackLength = ruleStack.length; + let previousPosition = position; + + if (position > line.length) { + break; + } + if (tokenCount >= this.getMaxTokensPerLine() - 1) { + truncatedLine = true; + break; + } + + let match = _.last(ruleStack).rule.getNextTags(ruleStack, string, stringWithNewLine, position, firstLine); + if (match) { + // Unmatched text before next tags + + if (position < match.tagsStart) { + tags.push(match.tagsStart - position); + tokenCount++; + } + tags.push.apply(tags, match.nextTags); + for (let j = 0; j < match.nextTags.length; j++) { + if (match.nextTags[j] >= 0) { + tokenCount++; + } + } + position = match.tagsEnd; + } else { + // Push filler token for unmatched text at end of line. + if (position < line.length || line.length === 0) { + tags.push(line.length - position); + } + break; + } + if (position === previousPosition) { + if (ruleStack.length === previousRuleStackLength) { + console.error(`Popping rule because it loops at column ${position} of line ${line}`, _.clone(ruleStack)); + + if (ruleStack.length > 1) { + let poppedStack = ruleStack.pop(); + let contentScopeName = poppedStack.contentScopeName; + let scopeName = poppedStack.scopeName; + if (contentScopeName) { + tags.push(this.endIdForScope(contentScopeName)); + } + if (scopeName) { + tags.push(this.endIdForScope(scopeName)); + } + } else { + if (position < line.length || (line.length === 0 && tags.length === 0)) { + tags.push(line.length - position); + } + break; + } + } else if (ruleStack.length > previousRuleStackLength) { // Stack size increased with zero length match + let slicedStack = ruleStack.slice(-2); + let penultimateRule = slicedStack[0].rule; + let lastRule = slicedStack[1].rule; + let popStack; + + if ((lastRule != null) && lastRule === penultimateRule) { + popStack = true; + } + // Same exact rule was pushed but position wasn't advanced + if (((lastRule != null ? lastRule.scopeName : void 0) != null) && penultimateRule.scopeName === lastRule.scopeName) { + popStack = true; + } + // Rule with same scope name as previous rule was pushed but position wasn't advanced. + if (popStack) { + ruleStack.pop(); + let lastSymbol = _.last(tags); + if (lastSymbol < 0 && lastSymbol === this.startIdForScope(lastRule.scopeName)) { + tags.pop(); // also pop the duplicated start scope if it was pushed + } + tags.push(line.length - position); + break; + } + } + } + } + if (truncatedLine) { + let tagCount = tags.length; + if (tags[tagCount - 1] > 0) { + tags[tagCount - 1] += inputLine.length - position; + } else { + tags.push(inputLine.length - position); + } + while (ruleStack.length > initialRuleStackLength) { + let poppedStack = ruleStack.pop(); + let scopeName = poppedStack.scopeName; + let contentScopeName = poppedStack.contentScopeName; + + if (contentScopeName) { + tags.push(this.endIdForScope(contentScopeName)); + } + if (scopeName) { + tags.push(this.endIdForScope(scopeName)); + } + } + } + for (let k = 0; k < ruleStack.length; k++) { + let rule = ruleStack[k].rule; + rule.clearAnchorPosition(); + } + if (compatibilityMode) { + return new TokenizeLineResult(inputLine, openScopeTags, tags, ruleStack, this.registry); + } else { + return { + line: inputLine, + tags: tags, + ruleStack: ruleStack + }; + } + } + + activate() { + return this.registration = this.registry.addGrammar(this); + } + + deactivate() { + this.emitter = new Emitter; + if (this.registration != null) { + this.registration.dispose(); + } + return this.registration = null; + } + + updateRules() { + this.initialRule = this.createRule({ + scopeName: this.scopeName, + patterns: this.rawPatterns + }); + this.repository = this.createRepository(); + return this.injections = new Injections(this, this.rawInjections); + } + + getInitialRule() { + return this.initialRule; + } + + getRepository() { + return this.repository; + } + + createRepository() { + let repository = {}; + for (const name in this.rawRepository) { + let data = this.rawRepository[name]; + if ((data.begin != null) || (data.match != null)) { + data = { + patterns: [data], + tempName: name + }; + } + repository[name] = this.createRule(data); + } + return repository; + } + + addIncludedGrammarScope(scope) { + if (!_.include(this.includedGrammarScopes, scope)) { + return this.includedGrammarScopes.push(scope); + } + } + + grammarUpdated(scopeName) { + if (!_.include(this.includedGrammarScopes, scopeName)) { + return false; + } + this.updateRules(); + this.registry.grammarUpdated(this.scopeName); + if (Grim.includeDeprecatedAPIs) { + this.emit('grammar-updated'); + } + this.emitter.emit('did-update'); + return true; + } + + startIdForScope(scope) { + return this.registry.startIdForScope(scope); + } + + endIdForScope(scope) { + return this.registry.endIdForScope(scope); + } + + scopeForId(id) { + return this.registry.scopeForId(id); + } + + createRule(options) { + return new Rule(this, this.registry, options); + } + + createPattern(options) { + return new Pattern(this, this.registry, options); + } + + getMaxTokensPerLine() { + return this.maxTokensPerLine; + } + + scopesFromStack(stack, rule, endPatternMatch) { + let scopes = []; + for (let i = 0; i < stack.length; i++) { + if (stack[i].scopeName) { + scopes.push(stack[i].scopeName); + } + if (stack[i].contentScopeName) { + scopes.push(stack[i].contentScopeName); + } + } + // Pop the last content name scope if the end pattern at the top of the stack + // was matched since only text between the begin/end patterns should have the content name scope. + if (endPatternMatch && (rule != null ? rule.contentScopeName : void 0) && rule === stack[stack.length -1]) { + scopes.pop(); + } + return scopes; + } +} + +Grammar.prototype.registration = null; // todo - find most exact way to implement this. Likely could be this.variable + + +if (Grim.includeDeprecatedAPIs) { + EmitterMixin = require('emissary').Emitter; + EmitterMixin.includeInto(Grammar); + Grammar.prototype.on = function(eventName) { + if (eventName === 'did-update') { + Grim.deprecate("Call Grammar::onDidUpdate instead"); + } else { + Grim.deprecate("Call explicit event subscription methods instead"); + } + return EmitterMixin.prototype.on.apply(this, arguments); + }; +} + +class TokenizeLineResult { + constructor(line, openScopeTags, tags, ruleStack, registry) { + this.line = line; + this.openScopeTags = openScopeTags; + this.tags = tags; + this.ruleStack = ruleStack; + this.registry = registry; + } + +} + +Object.defineProperty(TokenizeLineResult.prototype, 'tokens', { + get: function() { + return this.registry.decodeTokens(this.line, this.tags, this.openScopeTags); + } +}); + +module.exports = Grammar; diff --git a/lib/injections.js b/lib/injections.js new file mode 100644 index 0000000..a91088b --- /dev/null +++ b/lib/injections.js @@ -0,0 +1,58 @@ +const _ = require("underscore-plus"); +const Scanner = require("./scanner.js"); +const ScopeSelector = require("./scope-selector.js"); + +class Injections { + constructor(grammar, injections) { + this.grammar = grammar; + if (injections == null) { + injections = {}; + } + this.injections = []; + this.scanners = {}; + + for (const selector in injections) { + let values = injections[selector]; + if (!((values != null ? values.patterns != null ? values.patterns.length : void 0 : void 0) > 0)) { + continue; + } + let patterns = []; + for (let i = 0; i < values.patterns.length; i++) { + let pattern = this.grammar.createPattern(values.patterns[i]); + patterns.push.apply(patterns, pattern.getIncludedPatterns(this.grammar, patterns)); + } + this.injections.push({ + selector: new ScopeSelector(selector), + patterns: patterns + }); + } + } + + getScanner(injection) { + if (injection.scanner != null) { + return injection.scanner; + } + injection.scanner = new Scanner(injection.patterns); + return injection.scanner; + } + + getScanners(ruleStack) { + if (this.injections.length === 0) { + return []; + } + let scanners = []; + let scopes = this.grammar.scopesFromStack(ruleStack); + for (let i = 0; i < this.injections.length; i++) { + let injection = this.injections[i]; + if (!(injection.selector.matches(scopes))) { + continue; + } + let scanner = this.getScanner(injection); + scanners.push(scanner); + } + return scanners; + } + +} + +module.exports = Injections; diff --git a/lib/null-grammar.js b/lib/null-grammar.js new file mode 100644 index 0000000..73d3591 --- /dev/null +++ b/lib/null-grammar.js @@ -0,0 +1,15 @@ +const Grammar = require("./grammar.js"); + +// A grammar with no patterns that is always available from a {GrammarRegistry} +// even when it is completely empty. +class NullGrammar extends Grammar { + constructor(registry) { + super(registry, { name: "Null Grammar", scopeName: "text.plain.null-grammar" }); + } + + getScore() { + return 0; + } +} + +module.exports = NullGrammar; diff --git a/lib/pattern.js b/lib/pattern.js new file mode 100644 index 0000000..88c7f9e --- /dev/null +++ b/lib/pattern.js @@ -0,0 +1,341 @@ +const _ = require("underscore-plus"); +const AllCustomCaptureIndicesRegex = /\$(\d+)|\${(\d+):\/(downcase|upcase)}/g; +const AllDigitsRegex = /\\\d+/g; +const DigitRegex = /\\\d+/; +let __slice = [].slice; + +class Pattern { + constructor(grammar, registry, options) { + this.grammar = grammar; + this.registry = registry; + if (options == null) { + options = {}; + } + let { patterns, name, contentName, match, begin, end, captures, beginCaptures, endCaptures, applyEndPatternLast } = options; + this.include = options.include; + this.popRule = options.popRule; + this.hasBackReferences = options.hasBackReferences; + this.pushRule = null; + this.backReferences = null; + this.scopeName = name; + this.contentScopeName = contentName; + + if (match) { + if ((end || this.popRule) && (this.hasBackReferences != null ? this.hasBackReferences : this.hasBackReferences = DigitRegex.test(match))) { + this.match = match; + } else { + this.regexSource = match; + } + this.captures = captures; + } else if (begin) { + this.regexSource = begin; + this.captures = beginCaptures != null ? beginCaptures : captures; + let endPattern = this.grammar.createPattern({ + match: end, + captures: endCaptures != null ? endCaptures : captures, + popRule: true + }); + this.pushRule = this.grammar.createRule({ + scopeName: this.scopeName, + contentScopeName: this.contentScopeName, + patterns: patterns, + endPattern: endPattern, + applyEndPatternLast: applyEndPatternLast + }); + } + + if (this.captures != null) { + for (const group in this.captures) { + let capture = this.captures[group]; + if ((capture.patterns != null ? capture.patterns.length : void 0) > 0 && !capture.rule) { + capture.scopeName = this.scopeName; + capture.rule = this.grammar.createRule(capture); + } + } + } + this.anchored = this.hasAnchor(); + } + + getRegex(firstLine, position, anchorPosition) { + if (this.anchored) { + return this.replaceAnchor(firstLine, position, anchorPosition); + } else { + return this.regexSource; + } + } + + hasAnchor() { + if (!this.regexSource) { + return false; + } + let escape = false; + for (let i = 0; i < this.regexSource.length; i++) { + let character = this.regexSource[i]; + if (escape && (character === 'A' || character === 'G' || character === 'z')) { + return true; + } + escape = !escape && character === '\\'; + } + return false; + } + + replaceAnchor(firstLine, offset, anchor) { + let escaped = []; + let placeholder = '\uFFFF'; + let escape = false; + for (let i = 0; i < this.regexSource.length; i++) { + let character = this.regexSource[i]; + if (escape) { + switch (character) { + case 'A': + if (firstLine) { + escaped.push("\\" + character); + } else { + escaped.push(placeholder); + } + break; + case 'G': + if (offset === anchor) { + escaped.push("\\" + character); + } else { + escaped.push(placeholder); + } + break; + case 'z': + escaped.push('$(?!\n)(? { + let index = parseInt(match.slice(1)); + if (beginCaptures[index] != null) { + return _.escapeRegExp(beginCaptures[index]); + } else { + return "\\" + index; + } + }); + return this.grammar.createPattern({ + hasBackReferences: false, + match: resolvedMatch, + captures: this.captures, + popRule: this.popRule + }); + } + + ruleForInclude(baseGrammar, name) { + let hashIndex = name.indexOf("#"); + if (hashIndex === 0) { + return this.grammar.getRepository()[name.slice(1)]; + } else if (hashIndex >= 1) { + let grammarName = name.slice(0, +(hashIndex - 1) + 1 || 9e9); + let ruleName = name.slice(hashIndex + 1); + this.grammar.addIncludedGrammarScope(grammarName); + let _ref = this.registry.grammarForScopeName(grammarName); + return _ref != null ? _ref.getRepository()[ruleName] : void 0; + } else if (name === '$self') { + return this.grammar.getInitialRule(); + } else if (name === '$base') { + return baseGrammar.getInitialRule(); + } else { + this.grammar.addIncludedGrammarScope(name); + let _ref = this.registry.grammarForScopeName(name); + return _ref != null ? _ref.getInitialRule() : void 0; + } + } + + getIncludedPatterns(baseGrammar, included) { + if (this.include) { + let rule = this.ruleForInclude(baseGrammar, this.include); + let _ref = rule != null ? rule.getIncludedPatterns(baseGrammar, included) : void 0; + return _ref != null ? _ref : []; + } else { + return [this]; + } + } + + resolveScopeName(scopeName, line, captureIndices) { + return scopeName.replace(AllCustomCaptureIndicesRegex, (match, index, commandIndex, command) => { + let capture = captureIndices[parseInt(index != null ? index : commandIndex)]; + if (capture != null) { + let replacement = line.substring(capture.start, capture.end); + // Remove leading dots that would make the selector invalid + while(replacement[0] === '.') { + replacement = replacement.substring(1); + } + switch(command) { + case 'downcase': + return replacement.toLowerCase(); + case 'upcase': + return replacement.toUpperCase(); + default: + return replacement; + } + } else { + return match; + } + }); + } + + handleMatch(stack, line, captureIndices, rule, endPatternMatch) { + let scopeName, contentScopeName; + let tags = []; + let zeroWidthMatch = captureIndices[0].start === captureIndices[0].end; + if (this.popRule) { + // Pushing and popping a rule based on zero width matches at the same index + // leads to an infinite loop. We bail on parsing if we detect that case here. + if (zeroWidthMatch && _.last(stack).zeroWidthMatch && _.last(stack).rule.anchorPosition === captureIndices[0].end) { + return false; + } + contentScopeName = _.last(stack).contentScopeName; + if (contentScopeName) { + tags.push(this.grammar.endIdForScope(contentScopeName)); + } + } else if (this.scopeName) { + scopeName = this.resolveScopeName(this.scopeName, line, captureIndices); + tags.push(this.grammar.startIdForScope(scopeName)); + } + if (this.captures) { + tags.push.apply(tags, this.tagsForCaptureIndices(line, captureIndices.slice(), captureIndices, stack)); + } else { + if (captureIndices[0].end !== captureIndices[0].start) { + tags.push(captureIndices[0].end - captureIndices[0].start); + } + } + if (this.pushRule) { + let ruleToPush = this.pushRule.getRuleToPush(line, captureIndices); + ruleToPush.anchorPosition = captureIndices[0].end; + contentScopeName = ruleToPush.contentScopeName; + if (contentScopeName) { + contentScopeName = this.resolveScopeName(contentScopeName, line, captureIndices); + tags.push(this.grammar.startIdForScope(contentScopeName)); + } + stack.push({ + rule: ruleToPush, + scopeName: scopeName, + contentScopeName: contentScopeName, + zeroWidthMatch: zeroWidthMatch + }); + } else { + if (this.popRule) { + scopeName = stack.pop().scopeName; + } + if (scopeName) { + tags.push(this.grammar.endIdForScope(scopeName)); + } + } + return tags; + } + + tagsForCaptureRule(rule, line, captureStart, captureEnd, stack) { + let captureText = line.substring(captureStart, captureEnd); + let tags = rule.grammar.tokenizeLine(captureText, __slice.call(stack).concat([{ + rule: rule + }]), false, true, false).tags; + + // only accept non empty tokens that don't exceed the capture end + let openScopes = []; + let captureTags = []; + let offset = 0; + + for (let i = 0; i < tags.length; i++) { + let tag = tags[i]; + if (!(tag < 0 || (tag > 0 && offset < captureEnd))) { + continue; + } + captureTags.push(tag); + if (tag >= 0) { + offset += tag; + } else { + if (tag % 2 === 0) { + openScopes.pop(); + } else { + openScopes.push(tag); + } + } + } + // close any scopes left open by matching this rule since we don't pass our stack + while (openScopes.length > 0) { + captureTags.push(openScopes.pop() -1); + } + return captureTags; + } + + // Get the tokens for the capture indices. + // + // line - The string being tokenized. + // currentCaptureIndices - The current array of capture indices being + // processed into tokens. This method is called + // recursively and this array will be modified inside + // this method. + // allCaptureIndices - The array of all capture indices, this array will not + // be modified. + // stack - An array of rules. + // + // Returns a non-null but possibly empty array of tokens. + tagsForCaptureIndices(line, currentCaptureIndices, allCaptureIndices, stack) { + let parentCapture = currentCaptureIndices.shift(); + let tags = []; + let scope = this.captures[parentCapture.index] != null ? this.captures[parentCapture.index].name : void 0; + let captureTags, parentCaptureScope; + if (scope) { + parentCaptureScope = this.resolveScopeName(scope, line, allCaptureIndices); + tags.push(this.grammar.startIdForScope(parentCaptureScope)); + } + let captureRule = this.captures[parentCapture.index] != null ? this.captures[parentCapture.index].rule : void 0; + if (captureRule) { + captureTags = this.tagsForCaptureRule(captureRule, line, parentCapture.start, parentCapture.end, stack); + tags.push.apply(tags, captureTags); + // Consume child captures + while (currentCaptureIndices.length && currentCaptureIndices[0].start < parentCapture.end) { + currentCaptureIndices.shift(); + } + } else { + let previousChildCaptureEnd = parentCapture.start; + while (currentCaptureIndices.length && currentCaptureIndices[0].start < parentCapture.end) { + let childCapture = currentCaptureIndices[0]; + let emptyCapture = childCapture.end - childCapture.start === 0; + let captureHasNoScope = !this.captures[childCapture.index]; + if (emptyCapture || captureHasNoScope) { + currentCaptureIndices.shift(); + continue; + } + if (childCapture.start > previousChildCaptureEnd) { + tags.push(childCapture.start - previousChildCaptureEnd); + } + captureTags = this.tagsForCaptureIndices(line, currentCaptureIndices, allCaptureIndices, stack); + tags.push.apply(tags, captureTags); + previousChildCaptureEnd = childCapture.end; + } + if (parentCapture.end > previousChildCaptureEnd) { + tags.push(parentCapture.end - previousChildCaptureEnd); + } + } + if (parentCaptureScope) { + if (tags.length > 1) { + tags.push(this.grammar.endIdForScope(parentCaptureScope)); + } else { + tags.pop(); + } + } + return tags; + } + +} + +module.exports = Pattern; diff --git a/lib/rule.js b/lib/rule.js new file mode 100644 index 0000000..2b9319d --- /dev/null +++ b/lib/rule.js @@ -0,0 +1,194 @@ +const _ = require("underscore-plus"); +const Scanner = require("./scanner.js"); + +let __slice = [].slice; + +class Rule { + constructor(grammar, registry, _arg) { + let args = _arg != null ? _arg : {}; + this.grammar = grammar; + this.registry = registry; + this.patterns = []; + this.scopeName = args.scopeName; + this.contentScopeName = args.contentScopeName; + this.endPattern = args.endPattern; + this.applyEndPatternLast = args.applyEndPatternLast; + + let patterns = args.patterns; + let pattern; + + let ref1 = patterns != null ? patterns : []; + for (let i = 0; i < ref1.length; i++) { + pattern = ref1[i]; + if (!pattern.disabled) { + this.patterns.push(this.grammar.createPattern(pattern)); + } + } + if (this.endPattern && !this.endPattern.hasBackReferences) { + if (this.applyEndPatternLast) { + this.patterns.push(this.endPattern); + } else { + this.patterns.unshift(this.endPattern); + } + } + this.scannersByBaseGrammarName = {}; + this.createEndPattern = null; + this.anchorPosition = -1; + } + + getIncludedPatterns(baseGrammar, included) { + if (included == null) { + included = []; + } + if (_.include(included, this)) { + return []; + } + included = included.concat([this]); + let allPatterns = []; + for (let i = 0; i < this.patterns.length; i++) { + let pattern = this.patterns[i]; + allPatterns.push.apply(allPatterns, pattern.getIncludedPatterns(baseGrammar, included)); + } + return allPatterns; + } + + clearAnchorPosition() { + return this.anchorPosition = -1; + } + + getScanner(baseGrammar) { + let scanner = this.scannersByBaseGrammarName[baseGrammar.name] + if (scanner) { + return scanner; + } + let patterns = this.getIncludedPatterns(baseGrammar); + scanner = new Scanner(patterns); + this.scannersByBaseGrammarName[baseGrammar.name] = scanner; + return scanner; + } + + scanInjections(ruleStack, line, position, firstLine) { + let baseGrammar = ruleStack[0].rule.grammar; + let injections = baseGrammar.injections; + if (baseGrammar.injections) { + let ref = injections.getScanners(ruleStack); + for (let i = 0; i < ref.length; i++) { + let scanner = ref[i]; + let result = scanner.findNextMatch(line, firstLine, position, this.anchorPosition); + if (result != null) { + return result; + } + } + } + } + + normalizeCaptureIndices(line, captureIndices) { + let lineLength = line.length; + for (let i = 0; i < captureIndices.length; i++) { + let capture = captureIndices[i]; + capture.end = Math.min(capture.end, lineLength); + capture.start = Math.min(capture.start, lineLength); + } + } + + findNextMatch(ruleStack, lineWithNewline, position, firstLine) { + let baseGrammar = ruleStack[0].rule.grammar; + let results = []; + let scanner = this.getScanner(baseGrammar); + if (scanner.findNextMatch(lineWithNewline, firstLine, position, this.anchorPosition)) { + results.push(scanner.findNextMatch(lineWithNewline, firstLine, position, this.anchorPosition)); + } + let result = this.scanInjections(ruleStack, lineWithNewline, position, firstLine); + if (result) { + for (let i = 0; i < baseGrammar.injections.injections.length; i++) { + let injection = baseGrammar.injections.injections[i]; + if (injection.scanner === result.scanner) { + if (injection.selector.getPrefix(this.grammar.scopesFromStack(ruleStack)) === 'L') { + results.unshift(result); + } else { + // TODO: Prefixes can either be L, B, or R. + // R is assumed to mean "right", which is the default (add to end of stack). + // There's no documentation on B, however. + results.push(result); + } + } + } + } + let scopes = null; + for (let j = 0; j < this.registry.injectionGrammars.length; j++) { + let injectionGrammar = this.registry.injectionGrammars[j]; + if (injectionGrammar === this.grammar) { + continue; + } + if (injectionGrammar === baseGrammar) { + continue; + } + if (scopes == null) { + scopes = this.grammar.scopesFromStack(ruleStack); + } + if (injectionGrammar.injectionSelector.matches(scopes)) { + scanner = injectionGrammar.getInitialRule().getScanner(injectionGrammar, position, firstLine); + result = scanner.findNextMatch(lineWithNewline, firstLine, position, this.anchorPosition); + if (result) { + if (injectionGrammar.injectionSelector.getPrefix(scopes) === 'L') { + results.unshift(result); + } else { + // TODO: Prefixes can either be L, B, or R. + // R is assumed to mean "right", which is the default (add to end of stack). + // There's no documentation on B, however. + results.push(result); + } + } + } + } + if (results.length > 1) { + return _.min(results, (function(_this) { + return function(result) { + _this.normalizeCaptureIndices(lineWithNewline, result.captureIndices); + return result.captureIndices[0].start; + }; + })(this)); + } else if (results.length === 1) { + result = results[0]; + this.normalizeCaptureIndices(lineWithNewline, result.captureIndices); + return result; + } + } + + getNextTags(ruleStack, line, lineWithNewline, position, firstLine) { + let result = this.findNextMatch(ruleStack, lineWithNewline, position, firstLine); + if (result == null) { + return null; + } + let index = result.index; + let captureIndices = result.captureIndices; + let scanner = result.scanner; + let firstCapture = captureIndices[0]; + let endPatternMatch = this.endPattern === scanner.patterns[index]; + let nextTags = scanner.handleMatch(result, ruleStack, line, this, endPatternMatch); + if (nextTags) { + return { + nextTags: nextTags, + tagsStart: firstCapture.start, + tagsEnd: firstCapture.end + }; + } + } + + getRuleToPush(line, beginPatternCaptureIndices) { + if (this.endPattern.hasBackReferences) { + let rule = this.grammar.createRule({ + scopeName: this.scopeName, + contentScopeName: this.contentScopeName + }); + rule.endPattern = this.endPattern.resolveBackReferences(line, beginPatternCaptureIndices); + rule.patterns = [rule.endPattern].concat(__slice.call(this.patterns)); + return rule; + } else { + return this; + } + } + +} + +module.exports = Rule; diff --git a/lib/scanner.js b/lib/scanner.js new file mode 100644 index 0000000..bf841e7 --- /dev/null +++ b/lib/scanner.js @@ -0,0 +1,91 @@ + +const OnigScanner = require("oniguruma").OnigScanner; + +// Wrapper class for {OnigScanner} that caches them based on the presence of any +// anchor characters that change based on the current position being scanned. +// +// See {Pattern::replaceAnchor} for more details. + +class Scanner { + constructor(patterns) { + this.patterns = patterns != null ? patterns : []; + this.anchored = false; + + for (let i = 0; i < this.patterns.length; i++) { + if (!this.patterns[i].anchored) { + continue; + } + this.anchored = true; + break; + } + + this.anchoredScanner = null; + this.firstLineAnchoredScanner = null; + this.firstLineScanner = null; + this.scanner = null; + } + + // Create a new {OnigScanner} with the given options. + createScanner(firstLine, position, anchorPosition) { + let patterns = this.patterns.map((pattern) => { + return pattern.getRegex(firstLine, position, anchorPosition); + }); + return new OnigScanner(patterns); + } + + // Get the {OnigScanner} for the given position and options. + getScanner(firstLine, position, anchorPosition) { + if (!this.anchored) { + if (this.scanner == null) { + this.scanner = this.createScanner(firstLine, position, anchorPosition); + } + return this.scanner; + } + if (firstLine) { + if (position === anchorPosition) { + return this.firstLineAnchoredScanner != null ? this.firstLineAnchoredScanner : this.firstLineAnchoredScanner = this.createScanner(firstLine, position, anchorPosition); + } else { + return this.firstLineScanner != null ? this.firstLineScanner : this.firstLineScanner = this.createScanner(firstLine, position, anchorPosition); + } + } else if (position === anchorPosition) { + return this.anchoredScanner != null ? this.anchoredScanner : this.anchoredScanner = this.createScanner(firstLine, position, anchorPosition); + } else { + return this.scanner != null ? this.scanner : this.scanner = this.createScanner(firstLine, position, anchorPosition); + } + } + + // Public: Find the next match on the line start at the given position. + // + // line - the string being scanned. + // firstLine - true if the first line is being scanned. + // position = numeric position to start scanning at. + // anchorPosition - numeric position of the last anchored match. + // + // Returns an Object with details about the match or null if no match found. + findNextMatch(line, firstLine, position, anchorPosition) { + let scanner = this.getScanner(firstLine, position, anchorPosition); + let match = scanner.findNextMatchSync(line, position); + if (match != null) { + match.scanner = this; + } + return match; + } + + // Public: Handle the given match by calling `handleMatch` on the + // matched {Pattern} + // + // match - An object returned from a previous call to `findNextMatch` + // stack - An array of {Rule} objects. + // line - The string being scanned. + // rule - The rule that matched. + // endpatternMatch - true if the rule's end pattern matched. + // + // Returns an array of toekns representing the match. + handleMatch(match, stack, line, rule, endPatternMatch) { + let pattern = this.patterns[match.index]; + return pattern.handleMatch(stack, line, match.captureIndices, rule, endPatternMatch); + } + +} + +module.exports = Scanner; diff --git a/lib/scope-selector-matchers.js b/lib/scope-selector-matchers.js new file mode 100644 index 0000000..d52bcb9 --- /dev/null +++ b/lib/scope-selector-matchers.js @@ -0,0 +1,301 @@ +class SegmentMatcher { + constructor(segments) { + this.segment = segments[0].join('') + segments[1].join(''); + } + + matches(scope) { + return scope === this.segment; + } + + getPrefix(scope) { + + } + + toCssSelector() { + return this.segment.split('.').map((dotFragment) => { + return '.' + dotFragment.replace(/\+/g, '\\+'); + }).join(''); + } + + toCssSyntaxSelector() { + return this.segment.split('.').map((dotFragment) => { + return '.syntax--' + dotFragment.replace(/\+/g, '\\+'); + }).join(''); + } +} + +class TrueMatcher { + constructor() { + + } + + matches() { + return true; + } + + getPrefix(scopes) { + + } + + toCssSelector() { + return '*'; + } + + toCssSyntaxSelector() { + return '*'; + } +} + +class ScopeMatcher { + constructor(first, others) { + this.segments = [first]; + + for(let i = 0; i < others.length; i++) { + this.segments.push(others[i][1]); + } + } + + matches(scope) { + // This should be further worked on, but any logical changes caused failing tests. + let matcherSegment, matcherSegmentIndex, _i; + let lastDotIndex = 0; + for (matcherSegmentIndex = _i = 0; _i < this.segments.length; matcherSegmentIndex = ++_i) { + matcherSegment = this.segments[matcherSegmentIndex]; + if (lastDotIndex > scope.length) { + break; + } + let nextDotIndex = scope.indexOf('.', lastDotIndex); + if (nextDotIndex === -1) { + nextDotIndex = scope.length; + } + let scopeSegment = scope.substring(lastDotIndex, nextDotIndex); + if (!matcherSegment.matches(scopeSegment)) { + return false; + } + lastDotIndex = nextDotIndex + 1; + } + return matcherSegmentIndex === this.segments.length; + } + + getPrefix(scope) { + let scopeSegments = scope.split('.'); + if (scopeSegments.length < this.segments.length) { + return false; + } + + for (let i = 0; i < this.segments.length; i++) { + if (this.segments[i].matches(scopeSegments[i])) { + if (this.segments[i].prefix != null) { + return this.segments[i].prefix; + } + } + } + } + + toCssSelector() { + return this.segments.map((matcher) => { + return matcher.toCssSelector(); + }).join(''); + } + + toCssSyntaxSelector() { + return this.segments.map((matcher) => { + return matcher.toCssSyntaxSelector(); + }).join(''); + } +} + +class GroupMatcher { + constructor(prefix, selector) { + this.prefix = prefix != null ? prefix[0] : void 0; + this.selector = selector; + } + + matches(scopes) { + return this.selector.matches(scopes); + } + + getPrefix(scopes) { + if (this.selector.matches(scopes)) { + return this.prefix; + } + } + + toCssSelector() { + return this.selector.toCssSelector(); + } + + toCssSyntaxSelector() { + return this.selector.toCssSyntaxSelector(); + } +} + +class PathMatcher { + constructor(prefix, first, others) { + this.prefix = prefix != null ? prefix[0] : void 0; + this.matchers = [first]; + + for (let i = 0; i < others.length; i++) { + this.matchers.push(others[i][1]); + } + } + + matches(scopes) { + // This could likely be reduced further, but additional changes + // caused inconsistent tests. + let index = 0; + let matcher = this.matchers[index]; + for (let i = 0; i < scopes.length; i++) { + let scope = scopes[i]; + + if (matcher.matches(scope)) { + matcher = this.matchers[++index]; + } + if (matcher == null) { + return true; + } + } + return false; + } + + getPrefix(scopes) { + if (this.matches(scopes)) { + return this.prefix; + } + } + + toCssSelector() { + return this.matchers.map((matcher) => { + return matcher.toCssSelector(); + }).join(' '); + } + + toCssSyntaxSelector() { + return this.matchers.map((matcher) => { + return matcher.toCssSyntaxSelector(); + }).join(' '); + } + +} + +class OrMatcher { + constructor(left, right) { + this.left = left; + this.right = right; + } + + matches(scopes) { + return this.left.matches(scopes) || this.right.matches(scopes); + } + + getPrefix(scopes) { + return this.left.getPrefix(scopes) || this.right.getPrefix(scopes); + } + + toCssSelector() { + return `${this.left.toCssSelector()}, ${this.right.toCssSelector()}`; + } + + toCssSyntaxSelector() { + return `${this.left.toCssSyntaxSelector()}, ${this.right.toCssSyntaxSelector()}`; + } +} + +class AndMatcher { + constructor(left, right) { + this.left = left; + this.right = right; + } + + matches(scopes) { + return this.left.matches(scopes) && this.right.matches(scopes); + } + + getPrefix(scopes) { + if (this.left.matches(scopes) && this.right.matches(scopes)) { + return this.left.getPrefix(scopes); + } + } + + toCssSelector() { + if (this.right instanceof NegateMatcher) { + return `${this.left.toCssSelector()}${this.right.toCssSelector()}`; + } else { + return `${this.left.toCssSelector()} ${this.right.toCssSelector()}`; + } + } + + toCssSyntaxSelector() { + if (this.right instanceof NegateMatcher) { + return `${this.left.toCssSyntaxSelector()}${this.right.toCssSyntaxSelector()}`; + } else { + return `${this.left.toCssSyntaxSelector()} ${this.right.toCssSyntaxSelector()}`; + } + } +} + +class NegateMatcher { + constructor(matcher) { + this.matcher = matcher; + } + + matches(scopes) { + return !this.matcher.matches(scopes); + } + + getPrefix(scopes) { + + } + + toCssSelector() { + return `:not(${this.matcher.toCssSelector()})`; + } + + toCssSyntaxSelector() { + return `:not(${this.matcher.toCssSyntaxSelector()})`; + } +} + +class CompositeMatcher { + constructor(left, operator, right) { + switch(operator) { + case '|': + this.matcher = new OrMatcher(left, right); + break; + case '&': + this.matcher = new AndMatcher(left, right); + break; + case '-': + this.matcher = new AndMatcher(left, new NegateMatcher(right)); + break; + } + } + + matches(scopes) { + return this.matcher.matches(scopes); + } + + getPrefix(scopes) { + return this.matcher.getPrefix(scopes); + } + + toCssSelector() { + return this.matcher.toCssSelector(); + } + + toCssSyntaxSelector() { + return this.matcher.toCssSyntaxSelector(); + } +} + +module.exports = { + AndMatcher: AndMatcher, + CompositeMatcher: CompositeMatcher, + GroupMatcher: GroupMatcher, + NegateMatcher: NegateMatcher, + OrMatcher: OrMatcher, + PathMatcher: PathMatcher, + ScopeMatcher: ScopeMatcher, + SegmentMatcher: SegmentMatcher, + TrueMatcher: TrueMatcher +}; diff --git a/lib/scope-selector-parser.js b/lib/scope-selector-parser.js new file mode 100644 index 0000000..fcda326 --- /dev/null +++ b/lib/scope-selector-parser.js @@ -0,0 +1,960 @@ +/* + * Generated by PEG.js 0.10.0. + * + * http://pegjs.org/ + */ + +"use strict"; + +function peg$subclass(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor(); +} + +function peg$SyntaxError(message, expected, found, location) { + this.message = message; + this.expected = expected; + this.found = found; + this.location = location; + this.name = "SyntaxError"; + + if (typeof Error.captureStackTrace === "function") { + Error.captureStackTrace(this, peg$SyntaxError); + } +} + +peg$subclass(peg$SyntaxError, Error); + +peg$SyntaxError.buildMessage = function(expected, found) { + var DESCRIBE_EXPECTATION_FNS = { + literal: function(expectation) { + return "\"" + literalEscape(expectation.text) + "\""; + }, + + "class": function(expectation) { + var escapedParts = "", + i; + + for (i = 0; i < expectation.parts.length; i++) { + escapedParts += expectation.parts[i] instanceof Array + ? classEscape(expectation.parts[i][0]) + "-" + classEscape(expectation.parts[i][1]) + : classEscape(expectation.parts[i]); + } + + return "[" + (expectation.inverted ? "^" : "") + escapedParts + "]"; + }, + + any: function(expectation) { + return "any character"; + }, + + end: function(expectation) { + return "end of input"; + }, + + other: function(expectation) { + return expectation.description; + } + }; + + function hex(ch) { + return ch.charCodeAt(0).toString(16).toUpperCase(); + } + + function literalEscape(s) { + return s + .replace(/\\/g, '\\\\') + .replace(/"/g, '\\"') + .replace(/\0/g, '\\0') + .replace(/\t/g, '\\t') + .replace(/\n/g, '\\n') + .replace(/\r/g, '\\r') + .replace(/[\x00-\x0F]/g, function(ch) { return '\\x0' + hex(ch); }) + .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return '\\x' + hex(ch); }); + } + + function classEscape(s) { + return s + .replace(/\\/g, '\\\\') + .replace(/\]/g, '\\]') + .replace(/\^/g, '\\^') + .replace(/-/g, '\\-') + .replace(/\0/g, '\\0') + .replace(/\t/g, '\\t') + .replace(/\n/g, '\\n') + .replace(/\r/g, '\\r') + .replace(/[\x00-\x0F]/g, function(ch) { return '\\x0' + hex(ch); }) + .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return '\\x' + hex(ch); }); + } + + function describeExpectation(expectation) { + return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation); + } + + function describeExpected(expected) { + var descriptions = new Array(expected.length), + i, j; + + for (i = 0; i < expected.length; i++) { + descriptions[i] = describeExpectation(expected[i]); + } + + descriptions.sort(); + + if (descriptions.length > 0) { + for (i = 1, j = 1; i < descriptions.length; i++) { + if (descriptions[i - 1] !== descriptions[i]) { + descriptions[j] = descriptions[i]; + j++; + } + } + descriptions.length = j; + } + + switch (descriptions.length) { + case 1: + return descriptions[0]; + + case 2: + return descriptions[0] + " or " + descriptions[1]; + + default: + return descriptions.slice(0, -1).join(", ") + + ", or " + + descriptions[descriptions.length - 1]; + } + } + + function describeFound(found) { + return found ? "\"" + literalEscape(found) + "\"" : "end of input"; + } + + return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found."; +}; + +function peg$parse(input, options) { + options = options !== void 0 ? options : {}; + + var peg$FAILED = {}, + + peg$startRuleFunctions = { start: peg$parsestart }, + peg$startRuleFunction = peg$parsestart, + + peg$c0 = function(selector) { + return selector; + }, + peg$c1 = /^[a-zA-Z0-9+_]/, + peg$c2 = peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"], "+", "_"], false, false), + peg$c3 = /^[a-zA-Z0-9\-+_]/, + peg$c4 = peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"], "-", "+", "_"], false, false), + peg$c5 = function(segment) { + return new matchers.SegmentMatcher(segment); + }, + peg$c6 = /^[*]/, + peg$c7 = peg$classExpectation(["*"], false, false), + peg$c8 = function(scopeName) { + return new matchers.TrueMatcher(); + }, + peg$c9 = ".", + peg$c10 = peg$literalExpectation(".", false), + peg$c11 = function(first, others) { + return new matchers.ScopeMatcher(first, others); + }, + peg$c12 = /^[LRB]/, + peg$c13 = peg$classExpectation(["L", "R", "B"], false, false), + peg$c14 = ":", + peg$c15 = peg$literalExpectation(":", false), + peg$c16 = function(prefix, first, others) { + return new matchers.PathMatcher(prefix, first, others); + }, + peg$c17 = "(", + peg$c18 = peg$literalExpectation("(", false), + peg$c19 = ")", + peg$c20 = peg$literalExpectation(")", false), + peg$c21 = function(prefix, selector) { + return new matchers.GroupMatcher(prefix, selector); + }, + peg$c22 = "-", + peg$c23 = peg$literalExpectation("-", false), + peg$c24 = function(group) { + return new matchers.NegateMatcher(group); + }, + peg$c25 = function(path) { + return new matchers.NegateMatcher(path); + }, + peg$c26 = /^[|&\-]/, + peg$c27 = peg$classExpectation(["|", "&", "-"], false, false), + peg$c28 = function(left, operator, right) { + return new matchers.CompositeMatcher(left, operator, right); + }, + peg$c29 = ",", + peg$c30 = peg$literalExpectation(",", false), + peg$c31 = function(left, right) { + if (right) + return new matchers.OrMatcher(left, right); + else + return left; + }, + peg$c32 = /^[ \t]/, + peg$c33 = peg$classExpectation([" ", "\t"], false, false), + + peg$currPos = 0, + peg$savedPos = 0, + peg$posDetailsCache = [{ line: 1, column: 1 }], + peg$maxFailPos = 0, + peg$maxFailExpected = [], + peg$silentFails = 0, + + peg$result; + + if ("startRule" in options) { + if (!(options.startRule in peg$startRuleFunctions)) { + throw new Error("Can't start parsing from rule \"" + options.startRule + "\"."); + } + + peg$startRuleFunction = peg$startRuleFunctions[options.startRule]; + } + + function text() { + return input.substring(peg$savedPos, peg$currPos); + } + + function location() { + return peg$computeLocation(peg$savedPos, peg$currPos); + } + + function expected(description, location) { + location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos) + + throw peg$buildStructuredError( + [peg$otherExpectation(description)], + input.substring(peg$savedPos, peg$currPos), + location + ); + } + + function error(message, location) { + location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos) + + throw peg$buildSimpleError(message, location); + } + + function peg$literalExpectation(text, ignoreCase) { + return { type: "literal", text: text, ignoreCase: ignoreCase }; + } + + function peg$classExpectation(parts, inverted, ignoreCase) { + return { type: "class", parts: parts, inverted: inverted, ignoreCase: ignoreCase }; + } + + function peg$anyExpectation() { + return { type: "any" }; + } + + function peg$endExpectation() { + return { type: "end" }; + } + + function peg$otherExpectation(description) { + return { type: "other", description: description }; + } + + function peg$computePosDetails(pos) { + var details = peg$posDetailsCache[pos], p; + + if (details) { + return details; + } else { + p = pos - 1; + while (!peg$posDetailsCache[p]) { + p--; + } + + details = peg$posDetailsCache[p]; + details = { + line: details.line, + column: details.column + }; + + while (p < pos) { + if (input.charCodeAt(p) === 10) { + details.line++; + details.column = 1; + } else { + details.column++; + } + + p++; + } + + peg$posDetailsCache[pos] = details; + return details; + } + } + + function peg$computeLocation(startPos, endPos) { + var startPosDetails = peg$computePosDetails(startPos), + endPosDetails = peg$computePosDetails(endPos); + + return { + start: { + offset: startPos, + line: startPosDetails.line, + column: startPosDetails.column + }, + end: { + offset: endPos, + line: endPosDetails.line, + column: endPosDetails.column + } + }; + } + + function peg$fail(expected) { + if (peg$currPos < peg$maxFailPos) { return; } + + if (peg$currPos > peg$maxFailPos) { + peg$maxFailPos = peg$currPos; + peg$maxFailExpected = []; + } + + peg$maxFailExpected.push(expected); + } + + function peg$buildSimpleError(message, location) { + return new peg$SyntaxError(message, null, null, location); + } + + function peg$buildStructuredError(expected, found, location) { + return new peg$SyntaxError( + peg$SyntaxError.buildMessage(expected, found), + expected, + found, + location + ); + } + + function peg$parsestart() { + var s0, s1, s2, s3; + + s0 = peg$currPos; + s1 = peg$parse_(); + if (s1 !== peg$FAILED) { + s2 = peg$parseselector(); + if (s2 !== peg$FAILED) { + s3 = peg$parse_(); + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c0(s2); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + return s0; + } + + function peg$parsesegment() { + var s0, s1, s2, s3, s4, s5; + + s0 = peg$currPos; + s1 = peg$parse_(); + if (s1 !== peg$FAILED) { + s2 = peg$currPos; + s3 = []; + if (peg$c1.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c2); } + } + if (s4 !== peg$FAILED) { + while (s4 !== peg$FAILED) { + s3.push(s4); + if (peg$c1.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c2); } + } + } + } else { + s3 = peg$FAILED; + } + if (s3 !== peg$FAILED) { + s4 = []; + if (peg$c3.test(input.charAt(peg$currPos))) { + s5 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c4); } + } + while (s5 !== peg$FAILED) { + s4.push(s5); + if (peg$c3.test(input.charAt(peg$currPos))) { + s5 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c4); } + } + } + if (s4 !== peg$FAILED) { + s3 = [s3, s4]; + s2 = s3; + } else { + peg$currPos = s2; + s2 = peg$FAILED; + } + } else { + peg$currPos = s2; + s2 = peg$FAILED; + } + if (s2 !== peg$FAILED) { + s3 = peg$parse_(); + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c5(s2); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = peg$parse_(); + if (s1 !== peg$FAILED) { + if (peg$c6.test(input.charAt(peg$currPos))) { + s2 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c7); } + } + if (s2 !== peg$FAILED) { + s3 = peg$parse_(); + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c8(s2); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } + + return s0; + } + + function peg$parsescope() { + var s0, s1, s2, s3, s4, s5; + + s0 = peg$currPos; + s1 = peg$parsesegment(); + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 46) { + s4 = peg$c9; + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c10); } + } + if (s4 !== peg$FAILED) { + s5 = peg$parsesegment(); + if (s5 !== peg$FAILED) { + s4 = [s4, s5]; + s3 = s4; + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 46) { + s4 = peg$c9; + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c10); } + } + if (s4 !== peg$FAILED) { + s5 = peg$parsesegment(); + if (s5 !== peg$FAILED) { + s4 = [s4, s5]; + s3 = s4; + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } + if (s2 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c11(s1, s2); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + return s0; + } + + function peg$parsepath() { + var s0, s1, s2, s3, s4, s5, s6; + + s0 = peg$currPos; + s1 = peg$currPos; + if (peg$c12.test(input.charAt(peg$currPos))) { + s2 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c13); } + } + if (s2 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 58) { + s3 = peg$c14; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c15); } + } + if (s3 !== peg$FAILED) { + s2 = [s2, s3]; + s1 = s2; + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + if (s1 === peg$FAILED) { + s1 = null; + } + if (s1 !== peg$FAILED) { + s2 = peg$parsescope(); + if (s2 !== peg$FAILED) { + s3 = []; + s4 = peg$currPos; + s5 = peg$parse_(); + if (s5 !== peg$FAILED) { + s6 = peg$parsescope(); + if (s6 !== peg$FAILED) { + s5 = [s5, s6]; + s4 = s5; + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + while (s4 !== peg$FAILED) { + s3.push(s4); + s4 = peg$currPos; + s5 = peg$parse_(); + if (s5 !== peg$FAILED) { + s6 = peg$parsescope(); + if (s6 !== peg$FAILED) { + s5 = [s5, s6]; + s4 = s5; + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c16(s1, s2, s3); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + return s0; + } + + function peg$parsegroup() { + var s0, s1, s2, s3, s4, s5, s6; + + s0 = peg$currPos; + s1 = peg$currPos; + if (peg$c12.test(input.charAt(peg$currPos))) { + s2 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c13); } + } + if (s2 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 58) { + s3 = peg$c14; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c15); } + } + if (s3 !== peg$FAILED) { + s2 = [s2, s3]; + s1 = s2; + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + if (s1 === peg$FAILED) { + s1 = null; + } + if (s1 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 40) { + s2 = peg$c17; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c18); } + } + if (s2 !== peg$FAILED) { + s3 = peg$parse_(); + if (s3 !== peg$FAILED) { + s4 = peg$parseselector(); + if (s4 !== peg$FAILED) { + s5 = peg$parse_(); + if (s5 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 41) { + s6 = peg$c19; + peg$currPos++; + } else { + s6 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c20); } + } + if (s6 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c21(s1, s4); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + return s0; + } + + function peg$parseexpression() { + var s0, s1, s2, s3, s4; + + s0 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 45) { + s1 = peg$c22; + peg$currPos++; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c23); } + } + if (s1 !== peg$FAILED) { + s2 = peg$parse_(); + if (s2 !== peg$FAILED) { + s3 = peg$parsegroup(); + if (s3 !== peg$FAILED) { + s4 = peg$parse_(); + if (s4 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c24(s3); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 45) { + s1 = peg$c22; + peg$currPos++; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c23); } + } + if (s1 !== peg$FAILED) { + s2 = peg$parse_(); + if (s2 !== peg$FAILED) { + s3 = peg$parsepath(); + if (s3 !== peg$FAILED) { + s4 = peg$parse_(); + if (s4 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c25(s3); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$parsegroup(); + if (s0 === peg$FAILED) { + s0 = peg$parsepath(); + } + } + } + + return s0; + } + + function peg$parsecomposite() { + var s0, s1, s2, s3, s4, s5; + + s0 = peg$currPos; + s1 = peg$parseexpression(); + if (s1 !== peg$FAILED) { + s2 = peg$parse_(); + if (s2 !== peg$FAILED) { + if (peg$c26.test(input.charAt(peg$currPos))) { + s3 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c27); } + } + if (s3 !== peg$FAILED) { + s4 = peg$parse_(); + if (s4 !== peg$FAILED) { + s5 = peg$parsecomposite(); + if (s5 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c28(s1, s3, s5); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$parseexpression(); + } + + return s0; + } + + function peg$parseselector() { + var s0, s1, s2, s3, s4, s5; + + s0 = peg$currPos; + s1 = peg$parsecomposite(); + if (s1 !== peg$FAILED) { + s2 = peg$parse_(); + if (s2 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 44) { + s3 = peg$c29; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c30); } + } + if (s3 !== peg$FAILED) { + s4 = peg$parse_(); + if (s4 !== peg$FAILED) { + s5 = peg$parseselector(); + if (s5 === peg$FAILED) { + s5 = null; + } + if (s5 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c31(s1, s5); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$parsecomposite(); + } + + return s0; + } + + function peg$parse_() { + var s0, s1; + + s0 = []; + if (peg$c32.test(input.charAt(peg$currPos))) { + s1 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c33); } + } + while (s1 !== peg$FAILED) { + s0.push(s1); + if (peg$c32.test(input.charAt(peg$currPos))) { + s1 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c33); } + } + } + + return s0; + } + + var matchers = require('./scope-selector-matchers'); + + peg$result = peg$startRuleFunction(); + + if (peg$result !== peg$FAILED && peg$currPos === input.length) { + return peg$result; + } else { + if (peg$result !== peg$FAILED && peg$currPos < input.length) { + peg$fail(peg$endExpectation()); + } + + throw peg$buildStructuredError( + peg$maxFailExpected, + peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null, + peg$maxFailPos < input.length + ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1) + : peg$computeLocation(peg$maxFailPos, peg$maxFailPos) + ); + } +} + +module.exports = { + SyntaxError: peg$SyntaxError, + parse: peg$parse +}; diff --git a/lib/scope-selector.js b/lib/scope-selector.js new file mode 100644 index 0000000..f498e23 --- /dev/null +++ b/lib/scope-selector.js @@ -0,0 +1,50 @@ +const ScopeSelectorParser = require("./scope-selector-parser.js"); + +class ScopeSelector { + // Create a new scope selector + // + // source - A {String} to parse as a scope selector + constructor(source) { + this.matcher = ScopeSelectorParser.parse(source); + } + + // Check if this scope selector matches the scopes. + // + // scopes - An {Array} of {String}s or a single {String}. + // + // Returns a {Boolean}. + matches(scopes) { + if (typeof scopes === "string") { + scopes = [scopes]; + } + return this.matcher.matches(scopes); + } + + // Gets the prefix of this scope selector. + // + // scopes - An {Array} of {String}s or a single {String}. + // + // Returns a {String} if there is a prefix or undefined otherwise. + getPrefix(scopes) { + if (typeof scopes === "string") { + scopes = [scopes]; + } + return this.matcher.getPrefix(scopes); + } + + // Convert this TextMate scope selector to a CSS selector. + // + // Returns a {String}. + toCssSelector() { + return this.matcher.toCssSelector(); + } + + // Conver this TextMate scope selector to a CSS selector, prefixing scopes with `syntax--` + // + // Returns a {String} + toCssSyntaxSelector() { + return this.matcher.toCssSyntaxSelector(); + } +} + +module.exports = ScopeSelector; diff --git a/package-lock.json b/package-lock.json index 15b11ee..a9d129e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,28 +5,24 @@ "requires": true, "packages": { "": { + "name": "first-mate", "version": "7.4.3", "license": "MIT", "dependencies": { - "emissary": "^1", - "event-kit": "^2.2.0", + "emissary": "^1.3.3", + "event-kit": "^2.5.3", "fs-plus": "^3.0.0", - "grim": "^2.0.1", + "grim": "^2.0.3", "oniguruma": "^7.2.3", "season": "^6.0.2", "underscore-plus": "^1" }, "devDependencies": { - "coffee-script": "~1.7.0", - "grunt": "~0.4.1", - "grunt-atomdoc": "^1.0.0", - "grunt-cli": "~0.1.8", - "grunt-coffeelint": "0.0.6", - "grunt-contrib-coffee": "~0.9.0", - "grunt-peg": "~1.1.0", - "grunt-shell": "~0.2.2", + "grunt": "^0.4.0", + "grunt-atomdoc": "^1.0.1", + "grunt-cli": "^1.4.3", "jasmine-focused": "^1", - "rimraf": "~2.1.4" + "pegjs": "^0.10.0" } }, "node_modules/abbrev": { @@ -52,19 +48,10 @@ "node": ">=0.10.0" } }, - "node_modules/ansi-styles": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", - "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/argparse": { "version": "0.1.16", "resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz", - "integrity": "sha1-z9AeD7uj1srtBJ+9dY1A9lGW9Xw=", + "integrity": "sha512-LjmC2dNpdn2L4UzyoaIr11ELYoLn37ZFy9zObrQFHsSuOepeUEMKnM8w5KL4Tnrp2gy88rRuQt6Ky8Bjml+Baw==", "dev": true, "dependencies": { "underscore": "~1.7.0", @@ -74,18 +61,36 @@ "node_modules/argparse/node_modules/underscore": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", - "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=", + "integrity": "sha512-cp0oQQyZhUM1kpJDLdGO1jPZHgS/MpzoWYfe9+CM2h/QGDZlqwT2T3YGukuBdaNJ/CAPoeyAZRRHz8JFo176vA==", "dev": true }, "node_modules/argparse/node_modules/underscore.string": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz", - "integrity": "sha1-jN2PusTi0uoefi6Al8QvRCKA+Fs=", + "integrity": "sha512-yxkabuCaIBnzfIvX3kBxQqCs0ar/bfJwDnFEHJUm/ZrRVhT3IItdRF5cZjARLzEnyQYtIUhsZ2LG2j3HidFOFQ==", "dev": true, "engines": { "node": "*" } }, + "node_modules/array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", @@ -114,6 +119,18 @@ "concat-map": "0.0.1" } }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/builtins": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/builtins/-/builtins-0.0.4.tgz", @@ -128,32 +145,6 @@ "node": ">=0.10.0" } }, - "node_modules/chalk": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", - "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", - "dev": true, - "dependencies": { - "ansi-styles": "~1.0.0", - "has-color": "~0.1.0", - "strip-ansi": "~0.1.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/chalk/node_modules/strip-ansi": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", - "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=", - "dev": true, - "bin": { - "strip-ansi": "cli.js" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", @@ -196,112 +187,6 @@ "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", "dev": true }, - "node_modules/coffeelint": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/coffeelint/-/coffeelint-0.5.7.tgz", - "integrity": "sha1-PRJc3emV1kHL2ECwrFNsXN9vaNs=", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "coffee-script": ">=1.6.0", - "glob": ">=3.1.9", - "optimist": ">=0.2.8" - }, - "bin": { - "coffeelint": "bin/coffeelint" - } - }, - "node_modules/coffeelint/node_modules/coffee-script": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.6.2.tgz", - "integrity": "sha1-/ZyINpweQeMwegoWDXE/IlE8k7M=", - "deprecated": "CoffeeScript on NPM has moved to \"coffeescript\" (no hyphen)", - "dev": true, - "bin": { - "cake": "bin/cake", - "coffee": "bin/coffee" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/coffeelint/node_modules/glob": { - "version": "3.1.14", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.14.tgz", - "integrity": "sha1-+XpzHEHaZpXcg5RLuyF36aKbNj0=", - "dev": true, - "dependencies": { - "graceful-fs": "~1.1.2", - "inherits": "1", - "minimatch": "0.2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/coffeelint/node_modules/glob/node_modules/graceful-fs": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.1.14.tgz", - "integrity": "sha1-BweNtfY3f2Mh/Oqu30l94STclGU=", - "deprecated": "please upgrade to graceful-fs 4 for compatibility with current and future versions of Node.js", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/coffeelint/node_modules/glob/node_modules/inherits": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.0.tgz", - "integrity": "sha1-OOGXUoW/H3upyE2hArsSdxMirEg=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/coffeelint/node_modules/glob/node_modules/minimatch": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.9.tgz", - "integrity": "sha1-uAr5R+aoOoxo8m5UwNYSW6yfiH8=", - "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", - "dev": true, - "dependencies": { - "lru-cache": "~2.0.0", - "sigmund": "~1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/coffeelint/node_modules/glob/node_modules/minimatch/node_modules/lru-cache": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.0.4.tgz", - "integrity": "sha1-uLYa4JhIOF7Gdodg45wSPn45Voo=", - "dev": true - }, - "node_modules/coffeelint/node_modules/glob/node_modules/minimatch/node_modules/sigmund": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.0.tgz", - "integrity": "sha1-ZqKzp0mui1+4nv1PzAHclPvgIpY=", - "dev": true - }, - "node_modules/coffeelint/node_modules/optimist": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.5.tgz", - "integrity": "sha1-A2VLUkFwMDEtEJ85sVmCW2AwkwQ=", - "dev": true, - "dependencies": { - "wordwrap": "~0.0.2" - } - }, - "node_modules/coffeelint/node_modules/optimist/node_modules/wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/coffeestack": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/coffeestack/-/coffeestack-1.1.2.tgz", @@ -389,7 +274,7 @@ "node_modules/colors": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", - "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=", + "integrity": "sha512-OsSVtHK8Ir8r3+Fxw/b4jS1ZLPXkV6ZxDRJQzeD7qo0SqMXWrHDM71DgYzPMHY8SFJ0Ao+nNU2p1MmwdzKqPrw==", "dev": true, "engines": { "node": ">=0.1.90" @@ -432,7 +317,7 @@ "node_modules/dateformat": { "version": "1.0.2-1.2.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.2-1.2.3.tgz", - "integrity": "sha1-sCIMAt6YYXQztyhRz0fePfLNvuk=", + "integrity": "sha512-AXvW8g7tO4ilk5HgOWeDmPi/ZPaCnMJ+9Cg1I3p19w6mcvAAXBuuGEXAxybC+Djj1PSZUiHUcyoYu7WneCX8gQ==", "dev": true, "engines": { "node": "*" @@ -446,6 +331,15 @@ "node": ">=0.10.0" } }, + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/donna": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/donna/-/donna-1.0.16.tgz", @@ -485,7 +379,7 @@ "node_modules/emissary": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/emissary/-/emissary-1.3.3.tgz", - "integrity": "sha1-phjZLWgrIy0xER3DYlpd9mF5lgY=", + "integrity": "sha512-pD6FWNBSlEOzSJDCTcSGVLgNnGw5fnCvvGMdQ/TN43efeXZ/QTq8+hZoK3OOEXPRNjMmSJmeOnEJh+bWT5O8rQ==", "dependencies": { "es6-weak-map": "^0.1.2", "mixto": "1.x", @@ -560,19 +454,6 @@ "es6-symbol": "~2.0.1" } }, - "node_modules/esprima": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", - "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/event-kit": { "version": "2.5.3", "resolved": "https://registry.npmjs.org/event-kit/-/event-kit-2.5.3.tgz", @@ -584,15 +465,24 @@ "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", "dev": true }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, "engines": { - "node": ">= 0.8.0" + "node": ">=0.10.0" } }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, "node_modules/fileset": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/fileset/-/fileset-0.1.8.tgz", @@ -644,10 +534,22 @@ "node": "*" } }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/findup-sync": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.1.3.tgz", - "integrity": "sha1-fz56l7gjksZTvwZYm9hRkOk8NoM=", + "integrity": "sha512-yjftfYnF4ThYEvKEV/kEFR15dmtyXTAh3vQnzpJUoc7Naj5y1P0Ck7Zs1+Vroa00E3KT3IYsk756S+8WA5dNLw==", "dev": true, "dependencies": { "glob": "~3.2.9", @@ -660,7 +562,7 @@ "node_modules/findup-sync/node_modules/glob": { "version": "3.2.11", "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", - "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", + "integrity": "sha512-hVb0zwEZwC1FXSKRPFTeOtN7AArJcJlI6ULGLtrstaswKNlrTJqAA+1lYlSUop4vjA423xlBzqfVS3iWGlqJ+g==", "dev": true, "dependencies": { "inherits": "2", @@ -673,7 +575,7 @@ "node_modules/findup-sync/node_modules/lodash": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", + "integrity": "sha512-Kak1hi6/hYHGVPmdyiZijoQyz5x2iGVzs6w9GYB/HiXEtylY7tIoYEROMjvM1d9nXJqPOrG2MNPMn01bJ+S0Rw==", "dev": true, "engines": [ "node", @@ -683,7 +585,7 @@ "node_modules/findup-sync/node_modules/minimatch": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", - "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", + "integrity": "sha512-WFX1jI1AaxNTZVOHLBVazwTWKaQjoykSzCBNXB72vDTCzopQGtyP91tKdFK5cv1+qMwPyiTu1HqUriqplI8pcA==", "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", "dev": true, "dependencies": { @@ -694,6 +596,52 @@ "node": "*" } }, + "node_modules/fined": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/flagged-respawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", + "dev": true, + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/fs-plus": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/fs-plus/-/fs-plus-3.1.1.tgz", @@ -721,6 +669,12 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, "node_modules/gaze": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/gaze/-/gaze-0.3.4.tgz", @@ -748,15 +702,6 @@ "node": "*" } }, - "node_modules/getobject": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", - "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", @@ -773,49 +718,88 @@ "node": "*" } }, + "node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "node_modules/graceful-fs": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", - "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.1.14.tgz", + "integrity": "sha512-JUrvoFoQbLZpOZilKTXZX2e1EV0DTnuG5vsRFNFv4mPf/mnYbwNAFw/5x0rxeyaJslIdObGSgTTsMnM/acRaVw==", "deprecated": "please upgrade to graceful-fs 4 for compatibility with current and future versions of Node.js", "dev": true, + "optional": true, "engines": { "node": ">=0.4.0" } }, "node_modules/grim": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/grim/-/grim-2.0.2.tgz", - "integrity": "sha512-Qj7hTJRfd87E/gUgfvM0YIH/g2UA2SV6niv6BYXk1o6w4mhgv+QyYM1EjOJQljvzgEj4SqSsRWldXIeKHz3e3Q==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/grim/-/grim-2.0.3.tgz", + "integrity": "sha512-FM20Ump11qYLK9k9DbL8yzVpy+YBieya1JG15OeH8s+KbHq8kL4SdwRtURwIUHniSxb24EoBUpwKfFjGNVi4/Q==", "dependencies": { "event-kit": "^2.0.0" } }, "node_modules/grunt": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/grunt/-/grunt-0.4.5.tgz", - "integrity": "sha1-VpN81RlDJK3/bSB2MYMqnWuk5/A=", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/grunt/-/grunt-0.4.0.tgz", + "integrity": "sha512-dUrSRfUjz625nRf0/GJ90QEsTNAUlXNg1/G+W+J9BPNrCgXeTWO8Slj2YEG8MgnBdAHkR+96NupiFAat6tpY0g==", "dev": true, "dependencies": { "async": "~0.1.22", "coffee-script": "~1.3.3", - "colors": "~0.6.2", + "colors": "~0.6.0-1", "dateformat": "1.0.2-1.2.3", - "eventemitter2": "~0.4.13", - "exit": "~0.1.1", - "findup-sync": "~0.1.2", - "getobject": "~0.1.0", - "glob": "~3.1.21", - "grunt-legacy-log": "~0.1.0", - "grunt-legacy-util": "~0.2.0", + "eventemitter2": "~0.4.9", + "findup-sync": "~0.1.0", + "glob": "~3.1.17", "hooker": "~0.2.3", - "iconv-lite": "~0.2.11", - "js-yaml": "~2.0.5", - "lodash": "~0.9.2", - "minimatch": "~0.2.12", + "iconv-lite": "~0.2.5", + "js-yaml": "~1.0.1", + "lodash": "~0.9.0", + "minimatch": "~0.2.6", "nopt": "~1.0.10", - "rimraf": "~2.2.8", - "underscore.string": "~2.2.1", + "rimraf": "~2.0.2", + "underscore.string": "~2.2.0rc", "which": "~1.0.5" }, "engines": { @@ -825,7 +809,7 @@ "node_modules/grunt-atomdoc": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/grunt-atomdoc/-/grunt-atomdoc-1.0.1.tgz", - "integrity": "sha1-1fDuKVwBc/9N6p1AvCI+drjM8cc=", + "integrity": "sha512-/DM4+o+23UXNqeoQbuh48i+jVIR5xeXT8o+pB+nyffDTXLjWT+oqy6+9zXyceQImmGZ6EmYlCDKAXezuqKnmVw==", "dev": true, "dependencies": { "donna": "~1.0", @@ -836,233 +820,103 @@ } }, "node_modules/grunt-cli": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-0.1.13.tgz", - "integrity": "sha1-6evEBHYx9QEtkidww5N4EzytEPQ=", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.4.3.tgz", + "integrity": "sha512-9Dtx/AhVeB4LYzsViCjUQkd0Kw0McN2gYpdmGYKtE2a5Yt7v1Q+HYZVWhqXc/kGnxlMtqKDxSwotiGeFmkrCoQ==", "dev": true, "dependencies": { - "findup-sync": "~0.1.0", - "nopt": "~1.0.10", - "resolve": "~0.3.1" + "grunt-known-options": "~2.0.0", + "interpret": "~1.1.0", + "liftup": "~3.0.1", + "nopt": "~4.0.1", + "v8flags": "~3.2.0" }, "bin": { "grunt": "bin/grunt" }, "engines": { - "node": ">= 0.8.0" + "node": ">=10" } }, - "node_modules/grunt-coffeelint": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/grunt-coffeelint/-/grunt-coffeelint-0.0.6.tgz", - "integrity": "sha1-/NMBr9Z3XUGYCwDQHKYzG8kDBsw=", + "node_modules/grunt-cli/node_modules/nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", "dev": true, "dependencies": { - "coffeelint": "~0.5" - }, - "engines": { - "node": "*" + "abbrev": "1", + "osenv": "^0.1.4" }, - "peerDependencies": { - "grunt": "~0.4" + "bin": { + "nopt": "bin/nopt.js" } }, - "node_modules/grunt-contrib-coffee": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/grunt-contrib-coffee/-/grunt-contrib-coffee-0.9.0.tgz", - "integrity": "sha1-UZr1EF2hL+MWO7UOHKeAtslT77A=", + "node_modules/grunt-known-options": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-2.0.0.tgz", + "integrity": "sha512-GD7cTz0I4SAede1/+pAbmJRG44zFLPipVtdL9o3vqx9IEyb7b4/Y3s7r6ofI3CchR5GvYJ+8buCSioDv5dQLiA==", "dev": true, - "dependencies": { - "chalk": "~0.4.0", - "coffee-script": "~1.7.0", - "lodash": "~2.4.1" - }, "engines": { - "node": ">= 0.8.0" - }, - "peerDependencies": { - "grunt": "~0.4.0" + "node": ">=0.10.0" } }, - "node_modules/grunt-contrib-coffee/node_modules/lodash": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", + "node_modules/grunt/node_modules/async": { + "version": "0.1.22", + "resolved": "https://registry.npmjs.org/async/-/async-0.1.22.tgz", + "integrity": "sha512-2tEzliJmf5fHNafNwQLJXUasGzQCVctvsNkXmnlELHwypU0p08/rHohYvkqKIjyXpx+0rkrYv6QbhJ+UF4QkBg==", "dev": true, - "engines": [ - "node", - "rhino" - ] + "engines": { + "node": "*" + } }, - "node_modules/grunt-legacy-log": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-0.1.3.tgz", - "integrity": "sha1-7ClCboAwIa9ZAp+H0vnNczWgVTE=", + "node_modules/grunt/node_modules/coffee-script": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.3.3.tgz", + "integrity": "sha512-QjQ1T4BqyHv19k6XSfdhy/QLlIOhywz0ekBUCa9h71zYMJlfDTGan/Z1JXzYkZ6v8R+GhvL/p4FZPbPW8WNXlg==", + "deprecated": "CoffeeScript on NPM has moved to \"coffeescript\" (no hyphen)", "dev": true, - "dependencies": { - "colors": "~0.6.2", - "grunt-legacy-log-utils": "~0.1.1", - "hooker": "~0.2.3", - "lodash": "~2.4.1", - "underscore.string": "~2.3.3" + "bin": { + "cake": "bin/cake", + "coffee": "bin/coffee" }, "engines": { - "node": ">= 0.8.0" + "node": ">=0.4.0" } }, - "node_modules/grunt-legacy-log-utils": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-0.1.1.tgz", - "integrity": "sha1-wHBrndkGThFvNvI/5OawSGcsD34=", + "node_modules/grunt/node_modules/glob": { + "version": "3.1.21", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", + "integrity": "sha512-ANhy2V2+tFpRajE3wN4DhkNQ08KDr0Ir1qL12/cUe5+a7STEK8jkW4onUYuY8/06qAFuT5je7mjAqzx0eKI2tQ==", "dev": true, "dependencies": { - "colors": "~0.6.2", - "lodash": "~2.4.1", - "underscore.string": "~2.3.3" + "graceful-fs": "~1.2.0", + "inherits": "1", + "minimatch": "~0.2.11" }, "engines": { - "node": ">= 0.8.0" + "node": "*" } }, - "node_modules/grunt-legacy-log-utils/node_modules/lodash": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", - "dev": true, - "engines": [ - "node", - "rhino" - ] - }, - "node_modules/grunt-legacy-log-utils/node_modules/underscore.string": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", - "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/grunt-legacy-log/node_modules/lodash": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", - "dev": true, - "engines": [ - "node", - "rhino" - ] - }, - "node_modules/grunt-legacy-log/node_modules/underscore.string": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", - "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/grunt-legacy-util": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-0.2.0.tgz", - "integrity": "sha1-kzJIhNv343qf98Am3/RR2UqeVUs=", - "dev": true, - "dependencies": { - "async": "~0.1.22", - "exit": "~0.1.1", - "getobject": "~0.1.0", - "hooker": "~0.2.3", - "lodash": "~0.9.2", - "underscore.string": "~2.2.1", - "which": "~1.0.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/grunt-legacy-util/node_modules/async": { - "version": "0.1.22", - "resolved": "https://registry.npmjs.org/async/-/async-0.1.22.tgz", - "integrity": "sha1-D8GqoIig4+8Ovi2IMbqw3PiEUGE=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/grunt-peg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/grunt-peg/-/grunt-peg-1.1.0.tgz", - "integrity": "sha1-mXIenObicnRzkHfbh281otBc8qY=", - "dev": true, - "dependencies": { - "pegjs": "~0.8.0" - }, - "engines": { - "node": ">= 0.8.0" - }, - "peerDependencies": { - "grunt": "~0.4.1" - } - }, - "node_modules/grunt-shell": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/grunt-shell/-/grunt-shell-0.2.2.tgz", - "integrity": "sha1-f9470zu9SghxY428SGc4n3/ZX+Y=", - "dev": true, - "engines": { - "node": ">=0.8.0" - }, - "peerDependencies": { - "grunt": "~0.4.0" - } - }, - "node_modules/grunt/node_modules/async": { - "version": "0.1.22", - "resolved": "https://registry.npmjs.org/async/-/async-0.1.22.tgz", - "integrity": "sha1-D8GqoIig4+8Ovi2IMbqw3PiEUGE=", + "node_modules/grunt/node_modules/graceful-fs": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", + "integrity": "sha512-iiTUZ5vZ+2ZV+h71XAgwCSu6+NAizhFU3Yw8aC/hH5SQ3SnISqEqAek40imAFGtDcwJKNhXvSY+hzIolnLwcdQ==", + "deprecated": "please upgrade to graceful-fs 4 for compatibility with current and future versions of Node.js", "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/grunt/node_modules/coffee-script": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.3.3.tgz", - "integrity": "sha1-FQ1rTLUiiUNp7+1qIQHCC8f0pPQ=", - "deprecated": "CoffeeScript on NPM has moved to \"coffeescript\" (no hyphen)", - "dev": true, - "bin": { - "cake": "bin/cake", - "coffee": "bin/coffee" - }, "engines": { "node": ">=0.4.0" } }, - "node_modules/grunt/node_modules/glob": { - "version": "3.1.21", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", - "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", - "dev": true, - "dependencies": { - "graceful-fs": "~1.2.0", - "inherits": "1", - "minimatch": "~0.2.11" - }, - "engines": { - "node": "*" - } - }, "node_modules/grunt/node_modules/inherits": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", - "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=", + "integrity": "sha512-Al67oatbRSo3RV5hRqIoln6Y5yMVbJSIn4jEJNL7VCImzq/kLr7vvb6sFRJXqr8rpHc/2kJOM+y0sPKN47VdzA==", "dev": true }, "node_modules/grunt/node_modules/minimatch": { "version": "0.2.14", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", - "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", + "integrity": "sha512-zZ+Jy8lVWlvqqeM8iZB7w7KmQkoJn8djM585z88rywrEbzoqawVa9FR5p2hwD+y74nfuKOjmNvi9gtWJNLqHvA==", "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", "dev": true, "dependencies": { @@ -1073,20 +927,35 @@ "node": "*" } }, - "node_modules/grunt/node_modules/rimraf": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", - "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", + "node_modules/grunt/node_modules/underscore.string": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.2.1.tgz", + "integrity": "sha512-3FVmhXqelrj6gfgp3Bn6tOavJvW0dNH2T+heTD38JRxIrAbiuzbqjknszoOYj3DyFB1nWiLj208Qt2no/L4cIA==", "dev": true, - "bin": { - "rimraf": "bin.js" + "engines": { + "node": "*" } }, - "node_modules/has-color": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", - "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=", + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "dependencies": { + "parse-passwd": "^1.0.0" + }, "engines": { "node": ">=0.10.0" } @@ -1094,7 +963,7 @@ "node_modules/hooker": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", - "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=", + "integrity": "sha512-t+UerCsQviSymAInD01Pw+Dn/usmz1sRO+3Zk1+lx8eg+WKpD2ulcwWqHHL0+aseRBr+3+vIhiG1K1JTwaIcTA==", "dev": true, "engines": { "node": "*" @@ -1103,7 +972,7 @@ "node_modules/iconv-lite": { "version": "0.2.11", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz", - "integrity": "sha1-HOYKOleGSiktEyH/RgnKS7llrcg=", + "integrity": "sha512-KhmFWgaQZY83Cbhi+ADInoUQ8Etn6BG5fikM9syeOjQltvR45h7cRKJ/9uvQEuD61I3Uju77yYce0/LhKVClQw==", "dev": true, "engines": { "node": ">=0.4.0" @@ -1123,6 +992,18 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/interpret": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", + "integrity": "sha512-CLM8SNMDu7C5psFCn6Wg/tgpj/bKAg7hc2gWqcuR9OD5Ft9PhBpIu8PLicPeis+xDd6YX2ncI8MCA64I9tftIA==", + "dev": true + }, "node_modules/invert-kv": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", @@ -1131,6 +1012,40 @@ "node": ">=0.10.0" } }, + "node_modules/is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "dependencies": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", @@ -1142,6 +1057,87 @@ "node": ">=0.10.0" } }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "dependencies": { + "is-unc-path": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "dependencies": { + "unc-path-regex": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/jasmine-focused": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/jasmine-focused/-/jasmine-focused-1.0.7.tgz", @@ -1203,13 +1199,12 @@ } }, "node_modules/js-yaml": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-2.0.5.tgz", - "integrity": "sha1-olrmUJmZ6X3yeMZxnaEb0Gh3Q6g=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-1.0.3.tgz", + "integrity": "sha512-UqzDrK8526iLQnHaXZDBiAwn+ubNakeOViDTn/jK/PvoV8Zbib1ldAgvEopGIH4JqolR3zKPIMmxi9c5RpZ+EA==", "dev": true, "dependencies": { - "argparse": "~ 0.1.11", - "esprima": "~ 1.0.2" + "argparse": "~ 0.1.3" }, "bin": { "js-yaml": "bin/js-yaml.js" @@ -1218,6 +1213,15 @@ "node": ">= 0.6.0" } }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", @@ -1229,10 +1233,44 @@ "node": ">=0.10.0" } }, + "node_modules/liftup": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/liftup/-/liftup-3.0.1.tgz", + "integrity": "sha512-yRHaiQDizWSzoXk3APcA71eOI/UuhEkNN9DiW2Tt44mhYzX4joFoCZlxsSOF7RyeLlfqzFLQI1ngFq3ggMPhOw==", + "dev": true, + "dependencies": { + "extend": "^3.0.2", + "findup-sync": "^4.0.0", + "fined": "^1.2.0", + "flagged-respawn": "^1.0.1", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.1", + "rechoir": "^0.7.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/liftup/node_modules/findup-sync": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/lodash": { "version": "0.9.2", "resolved": "https://registry.npmjs.org/lodash/-/lodash-0.9.2.tgz", - "integrity": "sha1-jzSZxSRdNG1oLlsNO0B2fgnxqSw=", + "integrity": "sha512-LVbt/rjK62gSbhehDVKL0vlaime4Y1IBixL+bKeNfoY4L2zab/jGrxU6Ka05tMA/zBxkTk5t3ivtphdyYupczw==", "dev": true, "engines": [ "node", @@ -1245,6 +1283,27 @@ "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", "dev": true }, + "node_modules/make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/marked": { "version": "0.3.19", "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz", @@ -1257,6 +1316,19 @@ "node": ">=0.10.0" } }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -1303,7 +1375,7 @@ "node_modules/nopt": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", "dev": true, "dependencies": { "abbrev": "1" @@ -1323,6 +1395,46 @@ "node": ">=0.10.0" } }, + "node_modules/object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", + "dev": true, + "dependencies": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==", + "dev": true, + "dependencies": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -1350,6 +1462,15 @@ "wordwrap": "~0.0.2" } }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/os-locale": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", @@ -1361,6 +1482,48 @@ "node": ">=0.10.0" } }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "node_modules/parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", + "dev": true, + "dependencies": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -1369,16 +1532,55 @@ "node": ">=0.10.0" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", + "dev": true, + "dependencies": { + "path-root-regex": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/pegjs": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/pegjs/-/pegjs-0.8.0.tgz", - "integrity": "sha1-l28GfaE+XFsVAcAXklZoolOBFWE=", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/pegjs/-/pegjs-0.10.0.tgz", + "integrity": "sha512-qI5+oFNEGi3L5HAxDwN2LA4Gg7irF70Zs25edhjld9QemOgp0CbvMtbFcMvFtEo1OityPrcCzkQFB8JP/hxgow==", "dev": true, "bin": { "pegjs": "bin/pegjs" }, "engines": { - "node": ">= 0.8" + "node": ">=0.10" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/property-accessors": { @@ -1390,6 +1592,18 @@ "mixto": "1.x" } }, + "node_modules/rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "dev": true, + "dependencies": { + "resolve": "^1.9.0" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/requirejs": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz", @@ -1404,24 +1618,48 @@ } }, "node_modules/resolve": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.3.1.tgz", - "integrity": "sha1-NMY0R8ZkxwWY0cmxJvxDsqJDEKQ=", - "dev": true + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } }, "node_modules/rimraf": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.1.4.tgz", - "integrity": "sha1-Wm62Lu2gaPUe3lDymz5c0i89m7I=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.0.3.tgz", + "integrity": "sha512-uR09PSoW2+1hW0hquRqxb+Ae2h6R5ls3OAy2oNekQFtqbSJkltkhKRa+OhZKoxWsN9195Gp1vg7sELDRoJ8a3w==", "dev": true, "optionalDependencies": { - "graceful-fs": "~1" + "graceful-fs": "~1.1" } }, "node_modules/season": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/season/-/season-6.0.2.tgz", - "integrity": "sha1-naWPsd3SSCTXYhstxjpxI7UCF7Y=", + "integrity": "sha512-5eq1ZKvsIUTkefE/R6PhJyiDDaalPjmdhUPVMuOFh4Yz2n5pBl1COkzNlxQyI8BXEBEIu1nJeJqJPVD0c3vycQ==", "dependencies": { "cson-parser": "^1.3.0", "fs-plus": "^3.0.0", @@ -1473,6 +1711,18 @@ "node": ">=0.10.0" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/tello": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/tello/-/tello-1.0.7.tgz", @@ -1493,6 +1743,27 @@ "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", "dev": true }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/underscore": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", @@ -1507,14 +1778,42 @@ } }, "node_modules/underscore.string": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.2.1.tgz", - "integrity": "sha1-18D6KvXVoaZ/QlPa7pgTLnM/Dxk=", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.6.tgz", + "integrity": "sha512-VoC83HWXmCrF6rgkyxS9GHv8W9Q5nhMKho+OadDJGzL2oDYbYEppBaCMH6pFlwLeqj2QS+hhkw2kpXkSdD1JxQ==", "dev": true, + "dependencies": { + "sprintf-js": "^1.1.1", + "util-deprecate": "^1.0.2" + }, "engines": { "node": "*" } }, + "node_modules/underscore.string/node_modules/sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/v8flags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/walkdir": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.3.2.tgz", @@ -1527,7 +1826,7 @@ "node_modules/which": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz", - "integrity": "sha1-RgwdoPgQED0DIam2M6+eV15kSG8=", + "integrity": "sha512-E87fdQ/eRJr9W1X4wTPejNy9zTW3FI2vpCZSJ/HAY+TkjKVC0TUm1jk6vn2Z7qay0DQy0+RBGdXxj+RmmiGZKQ==", "dev": true, "bin": { "which": "bin/which" @@ -1618,16 +1917,10 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, - "ansi-styles": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", - "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=", - "dev": true - }, "argparse": { "version": "0.1.16", "resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz", - "integrity": "sha1-z9AeD7uj1srtBJ+9dY1A9lGW9Xw=", + "integrity": "sha512-LjmC2dNpdn2L4UzyoaIr11ELYoLn37ZFy9zObrQFHsSuOepeUEMKnM8w5KL4Tnrp2gy88rRuQt6Ky8Bjml+Baw==", "dev": true, "requires": { "underscore": "~1.7.0", @@ -1637,17 +1930,29 @@ "underscore": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", - "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=", + "integrity": "sha512-cp0oQQyZhUM1kpJDLdGO1jPZHgS/MpzoWYfe9+CM2h/QGDZlqwT2T3YGukuBdaNJ/CAPoeyAZRRHz8JFo176vA==", "dev": true }, "underscore.string": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz", - "integrity": "sha1-jN2PusTi0uoefi6Al8QvRCKA+Fs=", + "integrity": "sha512-yxkabuCaIBnzfIvX3kBxQqCs0ar/bfJwDnFEHJUm/ZrRVhT3IItdRF5cZjARLzEnyQYtIUhsZ2LG2j3HidFOFQ==", "dev": true } } }, + "array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", + "dev": true + }, + "array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "dev": true + }, "async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", @@ -1676,6 +1981,15 @@ "concat-map": "0.0.1" } }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, "builtins": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/builtins/-/builtins-0.0.4.tgz", @@ -1687,25 +2001,6 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" }, - "chalk": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", - "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", - "dev": true, - "requires": { - "ansi-styles": "~1.0.0", - "has-color": "~0.1.0", - "strip-ansi": "~0.1.0" - }, - "dependencies": { - "strip-ansi": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", - "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=", - "dev": true - } - } - }, "cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", @@ -1738,91 +2033,6 @@ } } }, - "coffeelint": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/coffeelint/-/coffeelint-0.5.7.tgz", - "integrity": "sha1-PRJc3emV1kHL2ECwrFNsXN9vaNs=", - "dev": true, - "requires": { - "coffee-script": ">=1.6.0", - "glob": ">=3.1.9", - "optimist": ">=0.2.8" - }, - "dependencies": { - "coffee-script": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.6.2.tgz", - "integrity": "sha1-/ZyINpweQeMwegoWDXE/IlE8k7M=", - "dev": true - }, - "glob": { - "version": "3.1.14", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.14.tgz", - "integrity": "sha1-+XpzHEHaZpXcg5RLuyF36aKbNj0=", - "dev": true, - "requires": { - "graceful-fs": "~1.1.2", - "inherits": "1", - "minimatch": "0.2" - }, - "dependencies": { - "graceful-fs": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.1.14.tgz", - "integrity": "sha1-BweNtfY3f2Mh/Oqu30l94STclGU=", - "dev": true - }, - "inherits": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.0.tgz", - "integrity": "sha1-OOGXUoW/H3upyE2hArsSdxMirEg=", - "dev": true - }, - "minimatch": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.9.tgz", - "integrity": "sha1-uAr5R+aoOoxo8m5UwNYSW6yfiH8=", - "dev": true, - "requires": { - "lru-cache": "~2.0.0", - "sigmund": "~1.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.0.4.tgz", - "integrity": "sha1-uLYa4JhIOF7Gdodg45wSPn45Voo=", - "dev": true - }, - "sigmund": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.0.tgz", - "integrity": "sha1-ZqKzp0mui1+4nv1PzAHclPvgIpY=", - "dev": true - } - } - } - } - }, - "optimist": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.5.tgz", - "integrity": "sha1-A2VLUkFwMDEtEJ85sVmCW2AwkwQ=", - "dev": true, - "requires": { - "wordwrap": "~0.0.2" - }, - "dependencies": { - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", - "dev": true - } - } - } - } - }, "coffeestack": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/coffeestack/-/coffeestack-1.1.2.tgz", @@ -1895,7 +2105,7 @@ "colors": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", - "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=", + "integrity": "sha512-OsSVtHK8Ir8r3+Fxw/b4jS1ZLPXkV6ZxDRJQzeD7qo0SqMXWrHDM71DgYzPMHY8SFJ0Ao+nNU2p1MmwdzKqPrw==", "dev": true }, "concat-map": { @@ -1929,7 +2139,7 @@ "dateformat": { "version": "1.0.2-1.2.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.2-1.2.3.tgz", - "integrity": "sha1-sCIMAt6YYXQztyhRz0fePfLNvuk=", + "integrity": "sha512-AXvW8g7tO4ilk5HgOWeDmPi/ZPaCnMJ+9Cg1I3p19w6mcvAAXBuuGEXAxybC+Djj1PSZUiHUcyoYu7WneCX8gQ==", "dev": true }, "decamelize": { @@ -1937,6 +2147,12 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", + "dev": true + }, "donna": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/donna/-/donna-1.0.16.tgz", @@ -1964,7 +2180,7 @@ "emissary": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/emissary/-/emissary-1.3.3.tgz", - "integrity": "sha1-phjZLWgrIy0xER3DYlpd9mF5lgY=", + "integrity": "sha512-pD6FWNBSlEOzSJDCTcSGVLgNnGw5fnCvvGMdQ/TN43efeXZ/QTq8+hZoK3OOEXPRNjMmSJmeOnEJh+bWT5O8rQ==", "requires": { "es6-weak-map": "^0.1.2", "mixto": "1.x", @@ -2041,12 +2257,6 @@ "es6-symbol": "~2.0.1" } }, - "esprima": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", - "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=", - "dev": true - }, "event-kit": { "version": "2.5.3", "resolved": "https://registry.npmjs.org/event-kit/-/event-kit-2.5.3.tgz", @@ -2058,10 +2268,19 @@ "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", "dev": true }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true }, "fileset": { @@ -2108,10 +2327,19 @@ } } }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, "findup-sync": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.1.3.tgz", - "integrity": "sha1-fz56l7gjksZTvwZYm9hRkOk8NoM=", + "integrity": "sha512-yjftfYnF4ThYEvKEV/kEFR15dmtyXTAh3vQnzpJUoc7Naj5y1P0Ck7Zs1+Vroa00E3KT3IYsk756S+8WA5dNLw==", "dev": true, "requires": { "glob": "~3.2.9", @@ -2121,7 +2349,7 @@ "glob": { "version": "3.2.11", "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", - "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", + "integrity": "sha512-hVb0zwEZwC1FXSKRPFTeOtN7AArJcJlI6ULGLtrstaswKNlrTJqAA+1lYlSUop4vjA423xlBzqfVS3iWGlqJ+g==", "dev": true, "requires": { "inherits": "2", @@ -2131,13 +2359,13 @@ "lodash": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", + "integrity": "sha512-Kak1hi6/hYHGVPmdyiZijoQyz5x2iGVzs6w9GYB/HiXEtylY7tIoYEROMjvM1d9nXJqPOrG2MNPMn01bJ+S0Rw==", "dev": true }, "minimatch": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", - "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", + "integrity": "sha512-WFX1jI1AaxNTZVOHLBVazwTWKaQjoykSzCBNXB72vDTCzopQGtyP91tKdFK5cv1+qMwPyiTu1HqUriqplI8pcA==", "dev": true, "requires": { "lru-cache": "2", @@ -2146,6 +2374,40 @@ } } }, + "fined": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + } + }, + "flagged-respawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "dev": true + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "dev": true + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + }, "fs-plus": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/fs-plus/-/fs-plus-3.1.1.tgz", @@ -2172,6 +2434,12 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, "gaze": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/gaze/-/gaze-0.3.4.tgz", @@ -2194,12 +2462,6 @@ } } }, - "getobject": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", - "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=", - "dev": true - }, "glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", @@ -2213,64 +2475,96 @@ "path-is-absolute": "^1.0.0" } }, + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "dependencies": { + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, "graceful-fs": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", - "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", - "dev": true + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.1.14.tgz", + "integrity": "sha512-JUrvoFoQbLZpOZilKTXZX2e1EV0DTnuG5vsRFNFv4mPf/mnYbwNAFw/5x0rxeyaJslIdObGSgTTsMnM/acRaVw==", + "dev": true, + "optional": true }, "grim": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/grim/-/grim-2.0.2.tgz", - "integrity": "sha512-Qj7hTJRfd87E/gUgfvM0YIH/g2UA2SV6niv6BYXk1o6w4mhgv+QyYM1EjOJQljvzgEj4SqSsRWldXIeKHz3e3Q==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/grim/-/grim-2.0.3.tgz", + "integrity": "sha512-FM20Ump11qYLK9k9DbL8yzVpy+YBieya1JG15OeH8s+KbHq8kL4SdwRtURwIUHniSxb24EoBUpwKfFjGNVi4/Q==", "requires": { "event-kit": "^2.0.0" } }, "grunt": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/grunt/-/grunt-0.4.5.tgz", - "integrity": "sha1-VpN81RlDJK3/bSB2MYMqnWuk5/A=", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/grunt/-/grunt-0.4.0.tgz", + "integrity": "sha512-dUrSRfUjz625nRf0/GJ90QEsTNAUlXNg1/G+W+J9BPNrCgXeTWO8Slj2YEG8MgnBdAHkR+96NupiFAat6tpY0g==", "dev": true, "requires": { "async": "~0.1.22", "coffee-script": "~1.3.3", - "colors": "~0.6.2", + "colors": "~0.6.0-1", "dateformat": "1.0.2-1.2.3", - "eventemitter2": "~0.4.13", - "exit": "~0.1.1", - "findup-sync": "~0.1.2", - "getobject": "~0.1.0", - "glob": "~3.1.21", - "grunt-legacy-log": "~0.1.0", - "grunt-legacy-util": "~0.2.0", + "eventemitter2": "~0.4.9", + "findup-sync": "~0.1.0", + "glob": "~3.1.17", "hooker": "~0.2.3", - "iconv-lite": "~0.2.11", - "js-yaml": "~2.0.5", - "lodash": "~0.9.2", - "minimatch": "~0.2.12", + "iconv-lite": "~0.2.5", + "js-yaml": "~1.0.1", + "lodash": "~0.9.0", + "minimatch": "~0.2.6", "nopt": "~1.0.10", - "rimraf": "~2.2.8", - "underscore.string": "~2.2.1", + "rimraf": "~2.0.2", + "underscore.string": "~2.2.0rc", "which": "~1.0.5" }, "dependencies": { "async": { "version": "0.1.22", "resolved": "https://registry.npmjs.org/async/-/async-0.1.22.tgz", - "integrity": "sha1-D8GqoIig4+8Ovi2IMbqw3PiEUGE=", + "integrity": "sha512-2tEzliJmf5fHNafNwQLJXUasGzQCVctvsNkXmnlELHwypU0p08/rHohYvkqKIjyXpx+0rkrYv6QbhJ+UF4QkBg==", "dev": true }, "coffee-script": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.3.3.tgz", - "integrity": "sha1-FQ1rTLUiiUNp7+1qIQHCC8f0pPQ=", + "integrity": "sha512-QjQ1T4BqyHv19k6XSfdhy/QLlIOhywz0ekBUCa9h71zYMJlfDTGan/Z1JXzYkZ6v8R+GhvL/p4FZPbPW8WNXlg==", "dev": true }, "glob": { "version": "3.1.21", "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", - "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", + "integrity": "sha512-ANhy2V2+tFpRajE3wN4DhkNQ08KDr0Ir1qL12/cUe5+a7STEK8jkW4onUYuY8/06qAFuT5je7mjAqzx0eKI2tQ==", "dev": true, "requires": { "graceful-fs": "~1.2.0", @@ -2278,26 +2572,32 @@ "minimatch": "~0.2.11" } }, + "graceful-fs": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", + "integrity": "sha512-iiTUZ5vZ+2ZV+h71XAgwCSu6+NAizhFU3Yw8aC/hH5SQ3SnISqEqAek40imAFGtDcwJKNhXvSY+hzIolnLwcdQ==", + "dev": true + }, "inherits": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", - "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=", + "integrity": "sha512-Al67oatbRSo3RV5hRqIoln6Y5yMVbJSIn4jEJNL7VCImzq/kLr7vvb6sFRJXqr8rpHc/2kJOM+y0sPKN47VdzA==", "dev": true }, "minimatch": { "version": "0.2.14", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", - "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", + "integrity": "sha512-zZ+Jy8lVWlvqqeM8iZB7w7KmQkoJn8djM585z88rywrEbzoqawVa9FR5p2hwD+y74nfuKOjmNvi9gtWJNLqHvA==", "dev": true, "requires": { "lru-cache": "2", "sigmund": "~1.0.0" } }, - "rimraf": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", - "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", + "underscore.string": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.2.1.tgz", + "integrity": "sha512-3FVmhXqelrj6gfgp3Bn6tOavJvW0dNH2T+heTD38JRxIrAbiuzbqjknszoOYj3DyFB1nWiLj208Qt2no/L4cIA==", "dev": true } } @@ -2305,7 +2605,7 @@ "grunt-atomdoc": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/grunt-atomdoc/-/grunt-atomdoc-1.0.1.tgz", - "integrity": "sha1-1fDuKVwBc/9N6p1AvCI+drjM8cc=", + "integrity": "sha512-/DM4+o+23UXNqeoQbuh48i+jVIR5xeXT8o+pB+nyffDTXLjWT+oqy6+9zXyceQImmGZ6EmYlCDKAXezuqKnmVw==", "dev": true, "requires": { "donna": "~1.0", @@ -2313,151 +2613,64 @@ } }, "grunt-cli": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-0.1.13.tgz", - "integrity": "sha1-6evEBHYx9QEtkidww5N4EzytEPQ=", - "dev": true, - "requires": { - "findup-sync": "~0.1.0", - "nopt": "~1.0.10", - "resolve": "~0.3.1" - } - }, - "grunt-coffeelint": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/grunt-coffeelint/-/grunt-coffeelint-0.0.6.tgz", - "integrity": "sha1-/NMBr9Z3XUGYCwDQHKYzG8kDBsw=", - "dev": true, - "requires": { - "coffeelint": "~0.5" - } - }, - "grunt-contrib-coffee": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/grunt-contrib-coffee/-/grunt-contrib-coffee-0.9.0.tgz", - "integrity": "sha1-UZr1EF2hL+MWO7UOHKeAtslT77A=", - "dev": true, - "requires": { - "chalk": "~0.4.0", - "coffee-script": "~1.7.0", - "lodash": "~2.4.1" - }, - "dependencies": { - "lodash": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", - "dev": true - } - } - }, - "grunt-legacy-log": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-0.1.3.tgz", - "integrity": "sha1-7ClCboAwIa9ZAp+H0vnNczWgVTE=", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.4.3.tgz", + "integrity": "sha512-9Dtx/AhVeB4LYzsViCjUQkd0Kw0McN2gYpdmGYKtE2a5Yt7v1Q+HYZVWhqXc/kGnxlMtqKDxSwotiGeFmkrCoQ==", "dev": true, "requires": { - "colors": "~0.6.2", - "grunt-legacy-log-utils": "~0.1.1", - "hooker": "~0.2.3", - "lodash": "~2.4.1", - "underscore.string": "~2.3.3" + "grunt-known-options": "~2.0.0", + "interpret": "~1.1.0", + "liftup": "~3.0.1", + "nopt": "~4.0.1", + "v8flags": "~3.2.0" }, "dependencies": { - "lodash": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", - "dev": true - }, - "underscore.string": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", - "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=", - "dev": true + "nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "dev": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } } } }, - "grunt-legacy-log-utils": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-0.1.1.tgz", - "integrity": "sha1-wHBrndkGThFvNvI/5OawSGcsD34=", - "dev": true, - "requires": { - "colors": "~0.6.2", - "lodash": "~2.4.1", - "underscore.string": "~2.3.3" - }, - "dependencies": { - "lodash": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", - "dev": true - }, - "underscore.string": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", - "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=", - "dev": true - } - } + "grunt-known-options": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-2.0.0.tgz", + "integrity": "sha512-GD7cTz0I4SAede1/+pAbmJRG44zFLPipVtdL9o3vqx9IEyb7b4/Y3s7r6ofI3CchR5GvYJ+8buCSioDv5dQLiA==", + "dev": true }, - "grunt-legacy-util": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-0.2.0.tgz", - "integrity": "sha1-kzJIhNv343qf98Am3/RR2UqeVUs=", + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "requires": { - "async": "~0.1.22", - "exit": "~0.1.1", - "getobject": "~0.1.0", - "hooker": "~0.2.3", - "lodash": "~0.9.2", - "underscore.string": "~2.2.1", - "which": "~1.0.5" - }, - "dependencies": { - "async": { - "version": "0.1.22", - "resolved": "https://registry.npmjs.org/async/-/async-0.1.22.tgz", - "integrity": "sha1-D8GqoIig4+8Ovi2IMbqw3PiEUGE=", - "dev": true - } + "function-bind": "^1.1.1" } }, - "grunt-peg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/grunt-peg/-/grunt-peg-1.1.0.tgz", - "integrity": "sha1-mXIenObicnRzkHfbh281otBc8qY=", + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", "dev": true, "requires": { - "pegjs": "~0.8.0" + "parse-passwd": "^1.0.0" } }, - "grunt-shell": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/grunt-shell/-/grunt-shell-0.2.2.tgz", - "integrity": "sha1-f9470zu9SghxY428SGc4n3/ZX+Y=", - "dev": true, - "requires": {} - }, - "has-color": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", - "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=", - "dev": true - }, "hooker": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", - "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=", + "integrity": "sha512-t+UerCsQviSymAInD01Pw+Dn/usmz1sRO+3Zk1+lx8eg+WKpD2ulcwWqHHL0+aseRBr+3+vIhiG1K1JTwaIcTA==", "dev": true }, "iconv-lite": { "version": "0.2.11", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz", - "integrity": "sha1-HOYKOleGSiktEyH/RgnKS7llrcg=", + "integrity": "sha512-KhmFWgaQZY83Cbhi+ADInoUQ8Etn6BG5fikM9syeOjQltvR45h7cRKJ/9uvQEuD61I3Uju77yYce0/LhKVClQw==", "dev": true }, "inflight": { @@ -2474,11 +2687,48 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "interpret": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", + "integrity": "sha512-CLM8SNMDu7C5psFCn6Wg/tgpj/bKAg7hc2gWqcuR9OD5Ft9PhBpIu8PLicPeis+xDd6YX2ncI8MCA64I9tftIA==", + "dev": true + }, "invert-kv": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" }, + "is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "requires": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + } + }, + "is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", @@ -2487,6 +2737,66 @@ "number-is-nan": "^1.0.0" } }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "requires": { + "is-unc-path": "^1.0.0" + } + }, + "is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "requires": { + "unc-path-regex": "^0.1.2" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + }, "jasmine-focused": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/jasmine-focused/-/jasmine-focused-1.0.7.tgz", @@ -2508,6 +2818,7 @@ }, "jasmine-node": { "version": "git+ssh://git@github.com/kevinsawicki/jasmine-node.git#81af4f953a2b7dfb5bde8331c05362a4b464c5ef", + "integrity": "sha512-OvqXUF5P3qkt6qYIkMeTRfBRp0V2BcQYhmUfax40vP0CcjxNbXy1hKaxTj/fidXU72bp/zf8UEJd5DqZI+Ojlg==", "dev": true, "from": "jasmine-node@git+https://github.com/kevinsawicki/jasmine-node.git#81af4f953a2b7dfb5bde8331c05362a4b464c5ef", "requires": { @@ -2540,15 +2851,20 @@ } }, "js-yaml": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-2.0.5.tgz", - "integrity": "sha1-olrmUJmZ6X3yeMZxnaEb0Gh3Q6g=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-1.0.3.tgz", + "integrity": "sha512-UqzDrK8526iLQnHaXZDBiAwn+ubNakeOViDTn/jK/PvoV8Zbib1ldAgvEopGIH4JqolR3zKPIMmxi9c5RpZ+EA==", "dev": true, "requires": { - "argparse": "~ 0.1.11", - "esprima": "~ 1.0.2" + "argparse": "~ 0.1.3" } }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, "lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", @@ -2557,10 +2873,40 @@ "invert-kv": "^1.0.0" } }, + "liftup": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/liftup/-/liftup-3.0.1.tgz", + "integrity": "sha512-yRHaiQDizWSzoXk3APcA71eOI/UuhEkNN9DiW2Tt44mhYzX4joFoCZlxsSOF7RyeLlfqzFLQI1ngFq3ggMPhOw==", + "dev": true, + "requires": { + "extend": "^3.0.2", + "findup-sync": "^4.0.0", + "fined": "^1.2.0", + "flagged-respawn": "^1.0.1", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.1", + "rechoir": "^0.7.0", + "resolve": "^1.19.0" + }, + "dependencies": { + "findup-sync": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" + } + } + } + }, "lodash": { "version": "0.9.2", "resolved": "https://registry.npmjs.org/lodash/-/lodash-0.9.2.tgz", - "integrity": "sha1-jzSZxSRdNG1oLlsNO0B2fgnxqSw=", + "integrity": "sha512-LVbt/rjK62gSbhehDVKL0vlaime4Y1IBixL+bKeNfoY4L2zab/jGrxU6Ka05tMA/zBxkTk5t3ivtphdyYupczw==", "dev": true }, "lru-cache": { @@ -2569,12 +2915,37 @@ "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", "dev": true }, + "make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "dev": true + }, "marked": { "version": "0.3.19", "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz", "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==", "dev": true }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -2614,7 +2985,7 @@ "nopt": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", "dev": true, "requires": { "abbrev": "1" @@ -2625,6 +2996,37 @@ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, + "object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", + "dev": true, + "requires": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==", + "dev": true, + "requires": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -2651,6 +3053,12 @@ "wordwrap": "~0.0.2" } }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "dev": true + }, "os-locale": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", @@ -2659,15 +3067,75 @@ "lcid": "^1.0.0" } }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", + "dev": true, + "requires": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "dev": true + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", + "dev": true, + "requires": { + "path-root-regex": "^0.1.0" + } + }, + "path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", + "dev": true + }, "pegjs": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/pegjs/-/pegjs-0.8.0.tgz", - "integrity": "sha1-l28GfaE+XFsVAcAXklZoolOBFWE=", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/pegjs/-/pegjs-0.10.0.tgz", + "integrity": "sha512-qI5+oFNEGi3L5HAxDwN2LA4Gg7irF70Zs25edhjld9QemOgp0CbvMtbFcMvFtEo1OityPrcCzkQFB8JP/hxgow==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, "property-accessors": { @@ -2679,6 +3147,15 @@ "mixto": "1.x" } }, + "rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "dev": true, + "requires": { + "resolve": "^1.9.0" + } + }, "requirejs": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz", @@ -2686,24 +3163,39 @@ "dev": true }, "resolve": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.3.1.tgz", - "integrity": "sha1-NMY0R8ZkxwWY0cmxJvxDsqJDEKQ=", - "dev": true + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", + "dev": true, + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + } }, "rimraf": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.1.4.tgz", - "integrity": "sha1-Wm62Lu2gaPUe3lDymz5c0i89m7I=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.0.3.tgz", + "integrity": "sha512-uR09PSoW2+1hW0hquRqxb+Ae2h6R5ls3OAy2oNekQFtqbSJkltkhKRa+OhZKoxWsN9195Gp1vg7sELDRoJ8a3w==", "dev": true, "requires": { - "graceful-fs": "~1" + "graceful-fs": "~1.1" } }, "season": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/season/-/season-6.0.2.tgz", - "integrity": "sha1-naWPsd3SSCTXYhstxjpxI7UCF7Y=", + "integrity": "sha512-5eq1ZKvsIUTkefE/R6PhJyiDDaalPjmdhUPVMuOFh4Yz2n5pBl1COkzNlxQyI8BXEBEIu1nJeJqJPVD0c3vycQ==", "requires": { "cson-parser": "^1.3.0", "fs-plus": "^3.0.0", @@ -2743,6 +3235,12 @@ "ansi-regex": "^2.0.0" } }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, "tello": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/tello/-/tello-1.0.7.tgz", @@ -2762,6 +3260,21 @@ } } }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", + "dev": true + }, "underscore": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", @@ -2776,11 +3289,38 @@ } }, "underscore.string": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.2.1.tgz", - "integrity": "sha1-18D6KvXVoaZ/QlPa7pgTLnM/Dxk=", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.6.tgz", + "integrity": "sha512-VoC83HWXmCrF6rgkyxS9GHv8W9Q5nhMKho+OadDJGzL2oDYbYEppBaCMH6pFlwLeqj2QS+hhkw2kpXkSdD1JxQ==", + "dev": true, + "requires": { + "sprintf-js": "^1.1.1", + "util-deprecate": "^1.0.2" + }, + "dependencies": { + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "v8flags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, "walkdir": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.3.2.tgz", @@ -2790,7 +3330,7 @@ "which": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz", - "integrity": "sha1-RgwdoPgQED0DIam2M6+eV15kSG8=", + "integrity": "sha512-E87fdQ/eRJr9W1X4wTPejNy9zTW3FI2vpCZSJ/HAY+TkjKVC0TUm1jk6vn2Z7qay0DQy0+RBGdXxj+RmmiGZKQ==", "dev": true }, "window-size": { diff --git a/package.json b/package.json index 2819d22..b57666b 100644 --- a/package.json +++ b/package.json @@ -4,38 +4,34 @@ "description": "TextMate helpers", "main": "./lib/first-mate.js", "scripts": { - "test": "grunt test", - "prepare": "grunt prepublish", - "benchmark": "node_modules/.bin/coffee benchmark/benchmark.coffee" + "test": "jasmine-focused --coffee --captureExceptions spec", + "benchmark": "node_modules/.bin/coffee benchmark/benchmark.coffee", + "parse": "pegjs -o ./lib/scope-selector-parser.js ./src/scope-selector-parser.pegjs", + "docs": "grunt atomdoc" }, "repository": { "type": "git", - "url": "https://github.com/atom/first-mate" + "url": "https://github.com/pulsar-edit/first-mate" }, "bugs": { - "url": "https://github.com/atom/first-mate/issues" + "url": "https://github.com/pulsar-edit/first-mate/issues" }, "license": "MIT", - "homepage": "http://atom.github.io/first-mate", + "homepage": "http://github.com/pulsar-edit/first-mate", "dependencies": { - "emissary": "^1", - "event-kit": "^2.2.0", + "emissary": "^1.3.3", + "event-kit": "^2.5.3", "fs-plus": "^3.0.0", - "grim": "^2.0.1", + "grim": "^2.0.3", "oniguruma": "^7.2.3", "season": "^6.0.2", "underscore-plus": "^1" }, "devDependencies": { - "coffee-script": "~1.7.0", - "grunt": "~0.4.1", - "grunt-atomdoc": "^1.0.0", - "grunt-cli": "~0.1.8", - "grunt-coffeelint": "0.0.6", - "grunt-contrib-coffee": "~0.9.0", - "grunt-peg": "~1.1.0", - "grunt-shell": "~0.2.2", + "grunt": "^0.4.0", + "grunt-atomdoc": "^1.0.1", + "grunt-cli": "^1.4.3", "jasmine-focused": "^1", - "rimraf": "~2.1.4" + "pegjs": "^0.10.0" } } diff --git a/spec/grammar-registry-spec.coffee b/spec/grammar-registry-spec.coffee index 7944eb5..fc20741 100644 --- a/spec/grammar-registry-spec.coffee +++ b/spec/grammar-registry-spec.coffee @@ -1,5 +1,5 @@ path = require 'path' -GrammarRegistry = require '../src/grammar-registry' +GrammarRegistry = require '../lib/grammar-registry' describe "GrammarRegistry", -> registry = null diff --git a/spec/grammar-spec.coffee b/spec/grammar-spec.coffee index c68cbda..53b2152 100644 --- a/spec/grammar-spec.coffee +++ b/spec/grammar-spec.coffee @@ -1,8 +1,8 @@ path = require 'path' _ = require 'underscore-plus' fs = require 'fs-plus' -GrammarRegistry = require '../src/grammar-registry' -Grammar = require '../src/grammar' +GrammarRegistry = require '../lib/grammar-registry' +Grammar = require '../lib/grammar' describe "Grammar tokenization", -> [grammar, registry] = [] diff --git a/src/first-mate.coffee b/src/first-mate.coffee deleted file mode 100644 index ce2e07a..0000000 --- a/src/first-mate.coffee +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = - ScopeSelector: require './scope-selector' - GrammarRegistry: require './grammar-registry' - Grammar: require './grammar' - -# This allows this file to be processed with `electron-link` -Object.defineProperty(module.exports, 'OnigRegExp', { - get: -> require('oniguruma').OnigRegExp -}) diff --git a/src/grammar-registry.coffee b/src/grammar-registry.coffee deleted file mode 100644 index 264c9ef..0000000 --- a/src/grammar-registry.coffee +++ /dev/null @@ -1,252 +0,0 @@ -_ = require 'underscore-plus' -CSON = require 'season' -{Emitter, Disposable} = require 'event-kit' -Grim = require 'grim' - -Grammar = require './grammar' -NullGrammar = require './null-grammar' - -# Extended: Registry containing one or more grammars. -module.exports = -class GrammarRegistry - constructor: (options={}) -> - @maxTokensPerLine = options.maxTokensPerLine ? Infinity - @maxLineLength = options.maxLineLength ? Infinity - @nullGrammar = new NullGrammar(this) - @clear() - - clear: -> - @emitter = new Emitter - @grammars = [] - @grammarsByScopeName = {} - @injectionGrammars = [] - @grammarOverridesByPath = {} - @scopeIdCounter = -1 - @idsByScope = {} - @scopesById = {} - @addGrammar(@nullGrammar) - - ### - Section: Event Subscription - ### - - # Public: Invoke the given callback when a grammar is added to the registry. - # - # * `callback` {Function} to call when a grammar is added. - # * `grammar` {Grammar} that was added. - # - # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. - onDidAddGrammar: (callback) -> - @emitter.on 'did-add-grammar', callback - - # Public: Invoke the given callback when a grammar is updated due to a grammar - # it depends on being added or removed from the registry. - # - # * `callback` {Function} to call when a grammar is updated. - # * `grammar` {Grammar} that was updated. - # - # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. - onDidUpdateGrammar: (callback) -> - @emitter.on 'did-update-grammar', callback - - # Public: Invoke the given callback when a grammar is removed from the registry. - # - # * `callback` {Function} to call when a grammar is removed. - # * `grammar` {Grammar} that was removed. - # - # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. - onDidRemoveGrammar: (callback) -> - @emitter.on 'did-remove-grammar', callback - - ### - Section: Managing Grammars - ### - - # Public: Get all the grammars in this registry. - # - # Returns a non-empty {Array} of {Grammar} instances. - getGrammars: -> - _.clone(@grammars) - - # Public: Get a grammar with the given scope name. - # - # * `scopeName` A {String} such as `"source.js"`. - # - # Returns a {Grammar} or undefined. - grammarForScopeName: (scopeName) -> - @grammarsByScopeName[scopeName] - - # Public: Add a grammar to this registry. - # - # A 'grammar-added' event is emitted after the grammar is added. - # - # * `grammar` The {Grammar} to add. This should be a value previously returned - # from {::readGrammar} or {::readGrammarSync}. - # - # Returns a {Disposable} on which `.dispose()` can be called to remove the - # grammar. - addGrammar: (grammar) -> - @grammars.push(grammar) - @grammarsByScopeName[grammar.scopeName] = grammar - @injectionGrammars.push(grammar) if grammar.injectionSelector? - @grammarUpdated(grammar.scopeName) - @emit 'grammar-added', grammar if Grammar.includeDeprecatedAPIs - @emitter.emit 'did-add-grammar', grammar - new Disposable => @removeGrammar(grammar) - - removeGrammar: (grammar) -> - _.remove(@grammars, grammar) - delete @grammarsByScopeName[grammar.scopeName] - _.remove(@injectionGrammars, grammar) - @grammarUpdated(grammar.scopeName) - @emitter.emit 'did-remove-grammar', grammar - undefined - - # Public: Remove the grammar with the given scope name. - # - # * `scopeName` A {String} such as `"source.js"`. - # - # Returns the removed {Grammar} or undefined. - removeGrammarForScopeName: (scopeName) -> - grammar = @grammarForScopeName(scopeName) - @removeGrammar(grammar) if grammar? - grammar - - # Public: Read a grammar synchronously but don't add it to the registry. - # - # * `grammarPath` A {String} absolute file path to a grammar file. - # - # Returns a {Grammar}. - readGrammarSync: (grammarPath) -> - grammar = CSON.readFileSync(grammarPath) ? {} - if typeof grammar.scopeName is 'string' and grammar.scopeName.length > 0 - @createGrammar(grammarPath, grammar) - else - throw new Error("Grammar missing required scopeName property: #{grammarPath}") - - # Public: Read a grammar asynchronously but don't add it to the registry. - # - # * `grammarPath` A {String} absolute file path to a grammar file. - # * `callback` A {Function} to call when read with the following arguments: - # * `error` An {Error}, may be null. - # * `grammar` A {Grammar} or null if an error occured. - # - # Returns undefined. - readGrammar: (grammarPath, callback) -> - CSON.readFile grammarPath, (error, grammar={}) => - if error? - callback?(error) - else - if typeof grammar.scopeName is 'string' and grammar.scopeName.length > 0 - callback?(null, @createGrammar(grammarPath, grammar)) - else - callback?(new Error("Grammar missing required scopeName property: #{grammarPath}")) - - undefined - - # Public: Read a grammar synchronously and add it to this registry. - # - # * `grammarPath` A {String} absolute file path to a grammar file. - # - # Returns a {Grammar}. - loadGrammarSync: (grammarPath) -> - grammar = @readGrammarSync(grammarPath) - @addGrammar(grammar) - grammar - - # Public: Read a grammar asynchronously and add it to the registry. - # - # * `grammarPath` A {String} absolute file path to a grammar file. - # * `callback` A {Function} to call when loaded with the following arguments: - # * `error` An {Error}, may be null. - # * `grammar` A {Grammar} or null if an error occured. - # - # Returns undefined. - loadGrammar: (grammarPath, callback) -> - @readGrammar grammarPath, (error, grammar) => - if error? - callback?(error) - else - @addGrammar(grammar) - callback?(null, grammar) - - undefined - - startIdForScope: (scope) -> - unless id = @idsByScope[scope] - id = @scopeIdCounter - @scopeIdCounter -= 2 - @idsByScope[scope] = id - @scopesById[id] = scope - id - - endIdForScope: (scope) -> - @startIdForScope(scope) - 1 - - scopeForId: (id) -> - if (id % 2) is -1 - @scopesById[id] # start id - else - @scopesById[id + 1] # end id - - grammarUpdated: (scopeName) -> - for grammar in @grammars when grammar.scopeName isnt scopeName - if grammar.grammarUpdated(scopeName) - @emit 'grammar-updated', grammar if Grammar.includeDeprecatedAPIs - @emitter.emit 'did-update-grammar', grammar - return - - createGrammar: (grammarPath, object) -> - object.maxTokensPerLine ?= @maxTokensPerLine - object.maxLineLength ?= @maxLineLength - if object.limitLineLength is false - object.maxLineLength = Infinity - grammar = new Grammar(this, object) - grammar.path = grammarPath - grammar - - decodeTokens: (lineText, tags, scopeTags = [], fn) -> - offset = 0 - scopeNames = scopeTags.map (tag) => @scopeForId(tag) - - tokens = [] - for tag, index in tags - # positive numbers indicate string content with length equaling the number - if tag >= 0 - token = { - value: lineText.substring(offset, offset + tag) - scopes: scopeNames.slice() - } - token = fn(token, index) if fn? - tokens.push(token) - offset += tag - - # odd negative numbers are begin scope tags - else if (tag % 2) is -1 - scopeTags.push(tag) - scopeNames.push(@scopeForId(tag)) - - # even negative numbers are end scope tags - else - scopeTags.pop() - expectedScopeName = @scopeForId(tag + 1) - poppedScopeName = scopeNames.pop() - unless poppedScopeName is expectedScopeName - throw new Error("Expected popped scope to be #{expectedScopeName}, but it was #{poppedScopeName}") - - tokens - -if Grim.includeDeprecatedAPIs - EmitterMixin = require('emissary').Emitter - EmitterMixin.includeInto(GrammarRegistry) - - GrammarRegistry::on = (eventName) -> - switch eventName - when 'grammar-added' - Grim.deprecate("Call GrammarRegistry::onDidAddGrammar instead") - when 'grammar-updated' - Grim.deprecate("Call GrammarRegistry::onDidUpdateGrammar instead") - else - Grim.deprecate("Call explicit event subscription methods instead") - - EmitterMixin::on.apply(this, arguments) diff --git a/src/grammar.coffee b/src/grammar.coffee deleted file mode 100644 index cc11ad2..0000000 --- a/src/grammar.coffee +++ /dev/null @@ -1,292 +0,0 @@ -path = require 'path' - -_ = require 'underscore-plus' -fs = require 'fs-plus' -{OnigRegExp, OnigString} = require 'oniguruma' -{Emitter} = require 'event-kit' -Grim = require 'grim' - -Injections = require './injections' -Pattern = require './pattern' -Rule = require './rule' -ScopeSelector = require './scope-selector' - -# Extended: Grammar that tokenizes lines of text. -# -# This class should not be instantiated directly but instead obtained from -# a {GrammarRegistry} by calling {GrammarRegistry::loadGrammar}. -module.exports = -class Grammar - registration: null - - constructor: (@registry, options={}) -> - {@name, @fileTypes, @scopeName, @foldingStopMarker, @maxTokensPerLine, @maxLineLength} = options - {injections, injectionSelector, patterns, repository, firstLineMatch, contentRegex} = options - - @emitter = new Emitter - @repository = null - @initialRule = null - - if injectionSelector? - @injectionSelector = new ScopeSelector(injectionSelector) - else - @injectionSelector = null - - if firstLineMatch - @firstLineRegex = new OnigRegExp(firstLineMatch) - else - @firstLineRegex = null - - if contentRegex - @contentRegex = new OnigRegExp(contentRegex) - else - @contentRegex = null - - @fileTypes ?= [] - @includedGrammarScopes = [] - - @rawPatterns = patterns - @rawRepository = repository - @rawInjections = injections - - @updateRules() - - ### - Section: Event Subscription - ### - - # Public: Invoke the given callback when this grammar is updated due to a - # grammar it depends on being added or removed from the registry. - # - # * `callback` {Function} to call when this grammar is updated. - # - # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. - onDidUpdate: (callback) -> - @emitter.on 'did-update', callback - - ### - Section: Tokenizing - ### - - # Public: Tokenize all lines in the given text. - # - # * `text` A {String} containing one or more lines. - # - # Returns an {Array} of token arrays for each line tokenized. - tokenizeLines: (text, compatibilityMode=true) -> - lines = text.split('\n') - lastLine = lines.length - 1 - ruleStack = null - - scopes = [] - for line, lineNumber in lines - {tags, ruleStack} = @tokenizeLine(line, ruleStack, lineNumber is 0, compatibilityMode, lineNumber isnt lastLine) - @registry.decodeTokens(line, tags, scopes) - - # Public: Tokenize the line of text. - # - # * `line` A {String} of text to tokenize. - # * `ruleStack` An optional {Array} of rules previously returned from this - # method. This should be null when tokenizing the first line in the file. - # * `firstLine` A optional {Boolean} denoting whether this is the first line - # in the file which defaults to `false`. This should be `true` - # when tokenizing the first line in the file. - # - # Returns an {Object} containing the following properties: - # * `line` The {String} of text that was tokenized. - # * `tags` An {Array} of integer scope ids and strings. Positive ids - # indicate the beginning of a scope, and negative tags indicate the end. - # To resolve ids to scope names, call {GrammarRegistry::scopeForId} with the - # absolute value of the id. - # * `tokens` This is a dynamic property. Invoking it will incur additional - # overhead, but will automatically translate the `tags` into token objects - # with `value` and `scopes` properties. - # * `ruleStack` An {Array} of rules representing the tokenized state at the - # end of the line. These should be passed back into this method when - # tokenizing the next line in the file. - tokenizeLine: (inputLine, ruleStack, firstLine=false, compatibilityMode=true, appendNewLine=true) -> - tags = [] - - truncatedLine = false - if inputLine.length > @maxLineLength - line = inputLine.slice(0, @maxLineLength) - truncatedLine = true - else - line = inputLine - - string = new OnigString(line) - stringWithNewLine = if appendNewLine then new OnigString(line + '\n') else string - - if ruleStack? - ruleStack = ruleStack.slice() - if compatibilityMode - openScopeTags = [] - for {scopeName, contentScopeName} in ruleStack - openScopeTags.push(@registry.startIdForScope(scopeName)) if scopeName - openScopeTags.push(@registry.startIdForScope(contentScopeName)) if contentScopeName - else - openScopeTags = [] if compatibilityMode - {scopeName, contentScopeName} = @initialRule - ruleStack = [{rule: @initialRule, scopeName, contentScopeName}] - tags.push(@startIdForScope(@initialRule.scopeName)) if scopeName - tags.push(@startIdForScope(@initialRule.contentScopeName)) if contentScopeName - - initialRuleStackLength = ruleStack.length - position = 0 - tokenCount = 0 - - loop - previousRuleStackLength = ruleStack.length - previousPosition = position - - break if position > line.length - - if tokenCount >= @getMaxTokensPerLine() - 1 - truncatedLine = true - break - - if match = _.last(ruleStack).rule.getNextTags(ruleStack, string, stringWithNewLine, position, firstLine) - {nextTags, tagsStart, tagsEnd} = match - - # Unmatched text before next tags - if position < tagsStart - tags.push(tagsStart - position) - tokenCount++ - - tags.push(nextTags...) - tokenCount++ for tag in nextTags when tag >= 0 - position = tagsEnd - - else - # Push filler token for unmatched text at end of line - if position < line.length or line.length is 0 - tags.push(line.length - position) - break - - if position is previousPosition - if ruleStack.length is previousRuleStackLength - console.error("Popping rule because it loops at column #{position} of line '#{line}'", _.clone(ruleStack)) - if ruleStack.length > 1 - {scopeName, contentScopeName} = ruleStack.pop() - tags.push(@endIdForScope(contentScopeName)) if contentScopeName - tags.push(@endIdForScope(scopeName)) if scopeName - else - if position < line.length or (line.length is 0 and tags.length is 0) - tags.push(line.length - position) - break - else if ruleStack.length > previousRuleStackLength # Stack size increased with zero length match - [{rule: penultimateRule}, {rule: lastRule}] = ruleStack[-2..] - - # Same exact rule was pushed but position wasn't advanced - if lastRule? and lastRule is penultimateRule - popStack = true - - # Rule with same scope name as previous rule was pushed but position wasn't advanced - if lastRule?.scopeName? and penultimateRule.scopeName is lastRule.scopeName - popStack = true - - if popStack - ruleStack.pop() - lastSymbol = _.last(tags) - if lastSymbol < 0 and lastSymbol is @startIdForScope(lastRule.scopeName) - tags.pop() # also pop the duplicated start scope if it was pushed - tags.push(line.length - position) - break - - if truncatedLine - tagCount = tags.length - if tags[tagCount - 1] > 0 - tags[tagCount - 1] += inputLine.length - position - else - tags.push(inputLine.length - position) - while ruleStack.length > initialRuleStackLength - {scopeName, contentScopeName} = ruleStack.pop() - tags.push(@endIdForScope(contentScopeName)) if contentScopeName - tags.push(@endIdForScope(scopeName)) if scopeName - - rule.clearAnchorPosition() for {rule} in ruleStack - - if compatibilityMode - new TokenizeLineResult(inputLine, openScopeTags, tags, ruleStack, @registry) - else - {line: inputLine, tags, ruleStack} - - activate: -> - @registration = @registry.addGrammar(this) - - deactivate: -> - @emitter = new Emitter - @registration?.dispose() - @registration = null - - updateRules: -> - @initialRule = @createRule({@scopeName, patterns: @rawPatterns}) - @repository = @createRepository() - @injections = new Injections(this, @rawInjections) - - getInitialRule: -> @initialRule - - getRepository: -> @repository - - createRepository: -> - repository = {} - for name, data of @rawRepository - data = {patterns: [data], tempName: name} if data.begin? or data.match? - repository[name] = @createRule(data) - repository - - addIncludedGrammarScope: (scope) -> - @includedGrammarScopes.push(scope) unless _.include(@includedGrammarScopes, scope) - - grammarUpdated: (scopeName) -> - return false unless _.include(@includedGrammarScopes, scopeName) - @updateRules() - @registry.grammarUpdated(@scopeName) - @emit 'grammar-updated' if Grim.includeDeprecatedAPIs - @emitter.emit 'did-update' - true - - startIdForScope: (scope) -> @registry.startIdForScope(scope) - - endIdForScope: (scope) -> @registry.endIdForScope(scope) - - scopeForId: (id) -> @registry.scopeForId(id) - - createRule: (options) -> new Rule(this, @registry, options) - - createPattern: (options) -> new Pattern(this, @registry, options) - - getMaxTokensPerLine: -> - @maxTokensPerLine - - scopesFromStack: (stack, rule, endPatternMatch) -> - scopes = [] - for {scopeName, contentScopeName} in stack - scopes.push(scopeName) if scopeName - scopes.push(contentScopeName) if contentScopeName - - # Pop the last content name scope if the end pattern at the top of the stack - # was matched since only text between the begin/end patterns should have the - # content name scope - if endPatternMatch and rule?.contentScopeName and rule is stack[stack.length - 1] - scopes.pop() - - scopes - -if Grim.includeDeprecatedAPIs - EmitterMixin = require('emissary').Emitter - EmitterMixin.includeInto(Grammar) - - Grammar::on = (eventName) -> - if eventName is 'did-update' - Grim.deprecate("Call Grammar::onDidUpdate instead") - else - Grim.deprecate("Call explicit event subscription methods instead") - - EmitterMixin::on.apply(this, arguments) - -class TokenizeLineResult - constructor: (@line, @openScopeTags, @tags, @ruleStack, @registry) -> - - Object.defineProperty @prototype, 'tokens', get: -> - @registry.decodeTokens(@line, @tags, @openScopeTags) diff --git a/src/injections.coffee b/src/injections.coffee deleted file mode 100644 index 763159c..0000000 --- a/src/injections.coffee +++ /dev/null @@ -1,36 +0,0 @@ -_ = require 'underscore-plus' - -Scanner = require './scanner' -ScopeSelector = require './scope-selector' - -module.exports = -class Injections - constructor: (@grammar, injections={}) -> - @injections = [] - @scanners = {} - for selector, values of injections - continue unless values?.patterns?.length > 0 - patterns = [] - for regex in values.patterns - pattern = @grammar.createPattern(regex) - patterns.push(pattern.getIncludedPatterns(@grammar, patterns)...) - @injections.push - selector: new ScopeSelector(selector) - patterns: patterns - - getScanner: (injection) -> - return injection.scanner if injection.scanner? - - scanner = new Scanner(injection.patterns) - injection.scanner = scanner - scanner - - getScanners: (ruleStack) -> - return [] if @injections.length is 0 - - scanners = [] - scopes = @grammar.scopesFromStack(ruleStack) - for injection in @injections when injection.selector.matches(scopes) - scanner = @getScanner(injection) - scanners.push(scanner) - scanners diff --git a/src/null-grammar.coffee b/src/null-grammar.coffee deleted file mode 100644 index e0e401b..0000000 --- a/src/null-grammar.coffee +++ /dev/null @@ -1,12 +0,0 @@ -Grammar = require './grammar' - -# A grammar with no patterns that is always available from a {GrammarRegistry} -# even when it is completely empty. -module.exports = -class NullGrammar extends Grammar - constructor: (registry) -> - name = 'Null Grammar' - scopeName = 'text.plain.null-grammar' - super(registry, {name, scopeName}) - - getScore: -> 0 diff --git a/src/pattern.coffee b/src/pattern.coffee deleted file mode 100644 index 30a2c91..0000000 --- a/src/pattern.coffee +++ /dev/null @@ -1,249 +0,0 @@ -_ = require 'underscore-plus' - -AllCustomCaptureIndicesRegex = /\$(\d+)|\${(\d+):\/(downcase|upcase)}/g -AllDigitsRegex = /\\\d+/g -DigitRegex = /\\\d+/ - -module.exports = -class Pattern - constructor: (@grammar, @registry, options={}) -> - {name, contentName, match, begin, end, patterns} = options - {captures, beginCaptures, endCaptures, applyEndPatternLast} = options - {@include, @popRule, @hasBackReferences} = options - - @pushRule = null - @backReferences = null - @scopeName = name - @contentScopeName = contentName - - if match - if (end or @popRule) and @hasBackReferences ?= DigitRegex.test(match) - @match = match - else - @regexSource = match - @captures = captures - else if begin - @regexSource = begin - @captures = beginCaptures ? captures - endPattern = @grammar.createPattern({match: end, captures: endCaptures ? captures, popRule: true}) - @pushRule = @grammar.createRule({@scopeName, @contentScopeName, patterns, endPattern, applyEndPatternLast}) - - if @captures? - for group, capture of @captures - if capture.patterns?.length > 0 and not capture.rule - capture.scopeName = @scopeName - capture.rule = @grammar.createRule(capture) - - @anchored = @hasAnchor() - - getRegex: (firstLine, position, anchorPosition) -> - if @anchored - @replaceAnchor(firstLine, position, anchorPosition) - else - @regexSource - - hasAnchor: -> - return false unless @regexSource - escape = false - for character in @regexSource - return true if escape and character in ['A', 'G', 'z'] - escape = not escape and character is '\\' - false - - replaceAnchor: (firstLine, offset, anchor) -> - escaped = [] - placeholder = '\uFFFF' - escape = false - for character in @regexSource - if escape - switch character - when 'A' - if firstLine - escaped.push("\\#{character}") - else - escaped.push(placeholder) - when 'G' - if offset is anchor - escaped.push("\\#{character}") - else - escaped.push(placeholder) - when 'z' - escaped.push('$(?!\n)(? - beginCaptures = [] - - for {start, end} in beginCaptureIndices - beginCaptures.push(line.substring(start, end)) - - resolvedMatch = @match.replace AllDigitsRegex, (match) -> - index = parseInt(match[1..]) - if beginCaptures[index]? - _.escapeRegExp(beginCaptures[index]) - else - "\\#{index}" - - @grammar.createPattern({hasBackReferences: false, match: resolvedMatch, @captures, @popRule}) - - ruleForInclude: (baseGrammar, name) -> - hashIndex = name.indexOf('#') - if hashIndex is 0 - @grammar.getRepository()[name[1..]] - else if hashIndex >= 1 - grammarName = name[0..hashIndex-1] - ruleName = name[hashIndex+1..] - @grammar.addIncludedGrammarScope(grammarName) - @registry.grammarForScopeName(grammarName)?.getRepository()[ruleName] - else if name is '$self' - @grammar.getInitialRule() - else if name is '$base' - baseGrammar.getInitialRule() - else - @grammar.addIncludedGrammarScope(name) - @registry.grammarForScopeName(name)?.getInitialRule() - - getIncludedPatterns: (baseGrammar, included) -> - if @include - rule = @ruleForInclude(baseGrammar, @include) - rule?.getIncludedPatterns(baseGrammar, included) ? [] - else - [this] - - resolveScopeName: (scopeName, line, captureIndices) -> - resolvedScopeName = scopeName.replace AllCustomCaptureIndicesRegex, (match, index, commandIndex, command) -> - capture = captureIndices[parseInt(index ? commandIndex)] - if capture? - replacement = line.substring(capture.start, capture.end) - # Remove leading dots that would make the selector invalid - replacement = replacement.substring(1) while replacement[0] is '.' - switch command - when 'downcase' then replacement.toLowerCase() - when 'upcase' then replacement.toUpperCase() - else replacement - else - match - - handleMatch: (stack, line, captureIndices, rule, endPatternMatch) -> - tags = [] - - zeroWidthMatch = captureIndices[0].start is captureIndices[0].end - - if @popRule - # Pushing and popping a rule based on zero width matches at the same index - # leads to an infinite loop. We bail on parsing if we detect that case here. - if zeroWidthMatch and _.last(stack).zeroWidthMatch and _.last(stack).rule.anchorPosition is captureIndices[0].end - return false - - {contentScopeName} = _.last(stack) - tags.push(@grammar.endIdForScope(contentScopeName)) if contentScopeName - else if @scopeName - scopeName = @resolveScopeName(@scopeName, line, captureIndices) - tags.push(@grammar.startIdForScope(scopeName)) - - if @captures - tags.push(@tagsForCaptureIndices(line, captureIndices.slice(), captureIndices, stack)...) - else - {start, end} = captureIndices[0] - tags.push(end - start) unless end is start - - if @pushRule - ruleToPush = @pushRule.getRuleToPush(line, captureIndices) - ruleToPush.anchorPosition = captureIndices[0].end - {contentScopeName} = ruleToPush - if contentScopeName - contentScopeName = @resolveScopeName(contentScopeName, line, captureIndices) - tags.push(@grammar.startIdForScope(contentScopeName)) - stack.push({rule: ruleToPush, scopeName, contentScopeName, zeroWidthMatch}) - else - {scopeName} = stack.pop() if @popRule - tags.push(@grammar.endIdForScope(scopeName)) if scopeName - - tags - - tagsForCaptureRule: (rule, line, captureStart, captureEnd, stack) -> - captureText = line.substring(captureStart, captureEnd) - {tags} = rule.grammar.tokenizeLine(captureText, [stack..., {rule}], false, true, false) - - # only accept non empty tokens that don't exceed the capture end - openScopes = [] - captureTags = [] - offset = 0 - for tag in tags when tag < 0 or (tag > 0 and offset < captureEnd) - captureTags.push(tag) - if tag >= 0 - offset += tag - else - if tag % 2 is 0 - openScopes.pop() - else - openScopes.push(tag) - - # close any scopes left open by matching this rule since we don't pass our stack - while openScopes.length > 0 - captureTags.push(openScopes.pop() - 1) - - captureTags - - # Get the tokens for the capture indices. - # - # line - The string being tokenized. - # currentCaptureIndices - The current array of capture indices being - # processed into tokens. This method is called - # recursively and this array will be modified inside - # this method. - # allCaptureIndices - The array of all capture indices, this array will not - # be modified. - # stack - An array of rules. - # - # Returns a non-null but possibly empty array of tokens - tagsForCaptureIndices: (line, currentCaptureIndices, allCaptureIndices, stack) -> - parentCapture = currentCaptureIndices.shift() - - tags = [] - if scope = @captures[parentCapture.index]?.name - parentCaptureScope = @resolveScopeName(scope, line, allCaptureIndices) - tags.push(@grammar.startIdForScope(parentCaptureScope)) - - if captureRule = @captures[parentCapture.index]?.rule - captureTags = @tagsForCaptureRule(captureRule, line, parentCapture.start, parentCapture.end, stack) - tags.push(captureTags...) - # Consume child captures - while currentCaptureIndices.length and currentCaptureIndices[0].start < parentCapture.end - currentCaptureIndices.shift() - else - previousChildCaptureEnd = parentCapture.start - while currentCaptureIndices.length and currentCaptureIndices[0].start < parentCapture.end - childCapture = currentCaptureIndices[0] - - emptyCapture = childCapture.end - childCapture.start is 0 - captureHasNoScope = not @captures[childCapture.index] - if emptyCapture or captureHasNoScope - currentCaptureIndices.shift() - continue - - if childCapture.start > previousChildCaptureEnd - tags.push(childCapture.start - previousChildCaptureEnd) - - captureTags = @tagsForCaptureIndices(line, currentCaptureIndices, allCaptureIndices, stack) - tags.push(captureTags...) - previousChildCaptureEnd = childCapture.end - - if parentCapture.end > previousChildCaptureEnd - tags.push(parentCapture.end - previousChildCaptureEnd) - - if parentCaptureScope - if tags.length > 1 - tags.push(@grammar.endIdForScope(parentCaptureScope)) - else - tags.pop() - - tags diff --git a/src/rule.coffee b/src/rule.coffee deleted file mode 100644 index 84d7528..0000000 --- a/src/rule.coffee +++ /dev/null @@ -1,116 +0,0 @@ -_ = require 'underscore-plus' - -Scanner = require './scanner' - -module.exports = -class Rule - constructor: (@grammar, @registry, {@scopeName, @contentScopeName, patterns, @endPattern, @applyEndPatternLast}={}) -> - @patterns = [] - for pattern in patterns ? [] - @patterns.push(@grammar.createPattern(pattern)) unless pattern.disabled - - if @endPattern and not @endPattern.hasBackReferences - if @applyEndPatternLast - @patterns.push(@endPattern) - else - @patterns.unshift(@endPattern) - - @scannersByBaseGrammarName = {} - @createEndPattern = null - @anchorPosition = -1 - - getIncludedPatterns: (baseGrammar, included=[]) -> - return [] if _.include(included, this) - - included = included.concat([this]) - allPatterns = [] - for pattern in @patterns - allPatterns.push(pattern.getIncludedPatterns(baseGrammar, included)...) - allPatterns - - clearAnchorPosition: -> @anchorPosition = -1 - - getScanner: (baseGrammar) -> - return scanner if scanner = @scannersByBaseGrammarName[baseGrammar.name] - - patterns = @getIncludedPatterns(baseGrammar) - scanner = new Scanner(patterns) - @scannersByBaseGrammarName[baseGrammar.name] = scanner - scanner - - scanInjections: (ruleStack, line, position, firstLine) -> - baseGrammar = ruleStack[0].rule.grammar - if injections = baseGrammar.injections - for scanner in injections.getScanners(ruleStack) - result = scanner.findNextMatch(line, firstLine, position, @anchorPosition) - return result if result? - - normalizeCaptureIndices: (line, captureIndices) -> - lineLength = line.length - for capture in captureIndices - capture.end = Math.min(capture.end, lineLength) - capture.start = Math.min(capture.start, lineLength) - return - - findNextMatch: (ruleStack, lineWithNewline, position, firstLine) -> - baseGrammar = ruleStack[0].rule.grammar - results = [] - - scanner = @getScanner(baseGrammar) - if result = scanner.findNextMatch(lineWithNewline, firstLine, position, @anchorPosition) - results.push(result) - - if result = @scanInjections(ruleStack, lineWithNewline, position, firstLine) - for injection in baseGrammar.injections.injections - if injection.scanner is result.scanner - if injection.selector.getPrefix(@grammar.scopesFromStack(ruleStack)) is 'L' - results.unshift(result) - else - # TODO: Prefixes can either be L, B, or R. - # R is assumed to mean "right", which is the default (add to end of stack). - # There's no documentation on B, however. - results.push(result) - - scopes = null - for injectionGrammar in @registry.injectionGrammars - continue if injectionGrammar is @grammar - continue if injectionGrammar is baseGrammar - scopes ?= @grammar.scopesFromStack(ruleStack) - if injectionGrammar.injectionSelector.matches(scopes) - scanner = injectionGrammar.getInitialRule().getScanner(injectionGrammar, position, firstLine) - if result = scanner.findNextMatch(lineWithNewline, firstLine, position, @anchorPosition) - if injectionGrammar.injectionSelector.getPrefix(scopes) is 'L' - results.unshift(result) - else - # TODO: Prefixes can either be L, B, or R. - # R is assumed to mean "right", which is the default (add to end of stack). - # There's no documentation on B, however. - results.push(result) - - if results.length > 1 - _.min results, (result) => - @normalizeCaptureIndices(lineWithNewline, result.captureIndices) - result.captureIndices[0].start - else if results.length is 1 - [result] = results - @normalizeCaptureIndices(lineWithNewline, result.captureIndices) - result - - getNextTags: (ruleStack, line, lineWithNewline, position, firstLine) -> - result = @findNextMatch(ruleStack, lineWithNewline, position, firstLine) - return null unless result? - - {index, captureIndices, scanner} = result - [firstCapture] = captureIndices - endPatternMatch = @endPattern is scanner.patterns[index] - if nextTags = scanner.handleMatch(result, ruleStack, line, this, endPatternMatch) - {nextTags, tagsStart: firstCapture.start, tagsEnd: firstCapture.end} - - getRuleToPush: (line, beginPatternCaptureIndices) -> - if @endPattern.hasBackReferences - rule = @grammar.createRule({@scopeName, @contentScopeName}) - rule.endPattern = @endPattern.resolveBackReferences(line, beginPatternCaptureIndices) - rule.patterns = [rule.endPattern, @patterns...] - rule - else - this diff --git a/src/scanner.coffee b/src/scanner.coffee deleted file mode 100644 index 2d3660a..0000000 --- a/src/scanner.coffee +++ /dev/null @@ -1,68 +0,0 @@ -{OnigScanner} = require 'oniguruma' - -# Wrapper class for {OnigScanner} that caches them based on the presence of any -# anchor characters that change based on the current position being scanned. -# -# See {Pattern::replaceAnchor} for more details. -module.exports = -class Scanner - constructor: (@patterns=[]) -> - @anchored = false - for pattern in @patterns when pattern.anchored - @anchored = true - break - - @anchoredScanner = null - @firstLineAnchoredScanner = null - @firstLineScanner = null - @scanner = null - - # Create a new {OnigScanner} with the given options. - createScanner: (firstLine, position, anchorPosition) -> - patterns = @patterns.map (pattern) -> - pattern.getRegex(firstLine, position, anchorPosition) - scanner = new OnigScanner(patterns) - - # Get the {OnigScanner} for the given position and options. - getScanner: (firstLine, position, anchorPosition) -> - unless @anchored - @scanner ?= @createScanner(firstLine, position, anchorPosition) - return @scanner - - if firstLine - if position is anchorPosition - @firstLineAnchoredScanner ?= @createScanner(firstLine, position, anchorPosition) - else - @firstLineScanner ?= @createScanner(firstLine, position, anchorPosition) - else if position is anchorPosition - @anchoredScanner ?= @createScanner(firstLine, position, anchorPosition) - else - @scanner ?= @createScanner(firstLine, position, anchorPosition) - - # Public: Find the next match on the line start at the given position - # - # line - the string being scanned. - # firstLine - true if the first line is being scanned. - # position - numeric position to start scanning at. - # anchorPosition - numeric position of the last anchored match. - # - # Returns an Object with details about the match or null if no match found. - findNextMatch: (line, firstLine, position, anchorPosition) -> - scanner = @getScanner(firstLine, position, anchorPosition) - match = scanner.findNextMatchSync(line, position) - match?.scanner = this - match - - # Public: Handle the given match by calling `handleMatch` on the - # matched {Pattern}. - # - # match - An object returned from a previous call to `findNextMatch`. - # stack - An array of {Rule} objects. - # line - The string being scanned. - # rule - The rule that matched. - # endPatternMatch - true if the rule's end pattern matched. - # - # Returns an array of tokens representing the match. - handleMatch: (match, stack, line, rule, endPatternMatch) -> - pattern = @patterns[match.index] - pattern.handleMatch(stack, line, match.captureIndices, rule, endPatternMatch) diff --git a/src/scope-selector-matchers.coffee b/src/scope-selector-matchers.coffee deleted file mode 100644 index 346cf5a..0000000 --- a/src/scope-selector-matchers.coffee +++ /dev/null @@ -1,165 +0,0 @@ -class SegmentMatcher - constructor: (segments) -> - @segment = segments[0].join('') + segments[1].join('') - - matches: (scope) -> scope is @segment - - getPrefix: (scope) -> - - toCssSelector: -> - @segment.split('.').map((dotFragment) -> - '.' + dotFragment.replace(/\+/g, '\\+') - ).join('') - - toCssSyntaxSelector: -> - @segment.split('.').map((dotFragment) -> - '.syntax--' + dotFragment.replace(/\+/g, '\\+') - ).join('') - -class TrueMatcher - constructor: -> - - matches: -> true - - getPrefix: (scopes) -> - - toCssSelector: -> '*' - - toCssSyntaxSelector: -> '*' - -class ScopeMatcher - constructor: (first, others) -> - @segments = [first] - @segments.push(segment[1]) for segment in others - - matches: (scope) -> - lastDotIndex = 0 - for matcherSegment, matcherSegmentIndex in @segments - break if lastDotIndex > scope.length - - nextDotIndex = scope.indexOf('.', lastDotIndex) - nextDotIndex = scope.length if nextDotIndex is -1 - - scopeSegment = scope.substring(lastDotIndex, nextDotIndex) - return false unless matcherSegment.matches(scopeSegment) - - lastDotIndex = nextDotIndex + 1 - - matcherSegmentIndex is @segments.length - - getPrefix: (scope) -> - scopeSegments = scope.split('.') - return false if scopeSegments.length < @segments.length - - for segment, index in @segments - if segment.matches(scopeSegments[index]) - return segment.prefix if segment.prefix? - - toCssSelector: -> - @segments.map((matcher) -> matcher.toCssSelector()).join('') - - toCssSyntaxSelector: -> - @segments.map((matcher) -> matcher.toCssSyntaxSelector()).join('') - -class GroupMatcher - constructor: (prefix, selector) -> - @prefix = prefix?[0] - @selector = selector - - matches: (scopes) -> @selector.matches(scopes) - - getPrefix: (scopes) -> @prefix if @selector.matches(scopes) - - toCssSelector: -> @selector.toCssSelector() - - toCssSyntaxSelector: -> @selector.toCssSyntaxSelector() - -class PathMatcher - constructor: (prefix, first, others) -> - @prefix = prefix?[0] - @matchers = [first] - @matchers.push(matcher[1]) for matcher in others - - matches: (scopes) -> - index = 0 - matcher = @matchers[index] - for scope in scopes - matcher = @matchers[++index] if matcher.matches(scope) - return true unless matcher? - false - - getPrefix: (scopes) -> @prefix if @matches(scopes) - - toCssSelector: -> - @matchers.map((matcher) -> matcher.toCssSelector()).join(' ') - - toCssSyntaxSelector: -> - @matchers.map((matcher) -> matcher.toCssSyntaxSelector()).join(' ') - -class OrMatcher - constructor: (@left, @right) -> - - matches: (scopes) -> @left.matches(scopes) or @right.matches(scopes) - - getPrefix: (scopes) -> @left.getPrefix(scopes) or @right.getPrefix(scopes) - - toCssSelector: -> "#{@left.toCssSelector()}, #{@right.toCssSelector()}" - - toCssSyntaxSelector: -> "#{@left.toCssSyntaxSelector()}, #{@right.toCssSyntaxSelector()}" - -class AndMatcher - constructor: (@left, @right) -> - - matches: (scopes) -> @left.matches(scopes) and @right.matches(scopes) - - getPrefix: (scopes) -> @left.getPrefix(scopes) if @left.matches(scopes) and @right.matches(scopes) # The right side can't have prefixes - - toCssSelector: -> - if @right instanceof NegateMatcher - "#{@left.toCssSelector()}#{@right.toCssSelector()}" - else - "#{@left.toCssSelector()} #{@right.toCssSelector()}" - - toCssSyntaxSelector: -> - if @right instanceof NegateMatcher - "#{@left.toCssSyntaxSelector()}#{@right.toCssSyntaxSelector()}" - else - "#{@left.toCssSyntaxSelector()} #{@right.toCssSyntaxSelector()}" - -class NegateMatcher - constructor: (@matcher) -> - - matches: (scopes) -> not @matcher.matches(scopes) - - getPrefix: (scopes) -> - - toCssSelector: -> ":not(#{@matcher.toCssSelector()})" - - toCssSyntaxSelector: -> ":not(#{@matcher.toCssSyntaxSelector()})" - -class CompositeMatcher - constructor: (left, operator, right) -> - switch operator - when '|' then @matcher = new OrMatcher(left, right) - when '&' then @matcher = new AndMatcher(left, right) - when '-' then @matcher = new AndMatcher(left, new NegateMatcher(right)) - - matches: (scopes) -> @matcher.matches(scopes) - - getPrefix: (scopes) -> @matcher.getPrefix(scopes) - - toCssSelector: -> @matcher.toCssSelector() - - toCssSyntaxSelector: -> @matcher.toCssSyntaxSelector() - -module.exports = { - AndMatcher - CompositeMatcher - GroupMatcher - NegateMatcher - OrMatcher - PathMatcher - ScopeMatcher - SegmentMatcher - TrueMatcher -} diff --git a/src/scope-selector.coffee b/src/scope-selector.coffee deleted file mode 100644 index 214519d..0000000 --- a/src/scope-selector.coffee +++ /dev/null @@ -1,36 +0,0 @@ -ScopeSelectorParser = require '../lib/scope-selector-parser' - -module.exports = -class ScopeSelector - # Create a new scope selector. - # - # source - A {String} to parse as a scope selector. - constructor: (source) -> @matcher = ScopeSelectorParser.parse(source) - - # Check if this scope selector matches the scopes. - # - # scopes - An {Array} of {String}s or a single {String}. - # - # Returns a {Boolean}. - matches: (scopes) -> - scopes = [scopes] if typeof scopes is 'string' - @matcher.matches(scopes) - - # Gets the prefix of this scope selector. - # - # scopes - An {Array} of {String}s or a single {String}. - # - # Returns a {String} if there is a prefix or undefined otherwise. - getPrefix: (scopes) -> - scopes = [scopes] if typeof scopes is 'string' - @matcher.getPrefix(scopes) - - # Convert this TextMate scope selector to a CSS selector. - # - # Returns a {String}. - toCssSelector: -> @matcher.toCssSelector() - - # Convert this TextMate scope selector to a CSS selector, prefixing scopes with `syntax--`. - # - # Returns a {String}. - toCssSyntaxSelector: -> @matcher.toCssSyntaxSelector()