From 60c7c8a606321e5d251394d04168817c1933b827 Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Wed, 26 Feb 2014 08:31:53 -0800 Subject: [PATCH] add debugging properties to AST nodes (#589) --- lib/jsdoc/src/astnode.js | 23 +++++++- test/specs/jsdoc/src/astnode.js | 95 ++++++++++++++++++++++++++++++++- 2 files changed, 116 insertions(+), 2 deletions(-) diff --git a/lib/jsdoc/src/astnode.js b/lib/jsdoc/src/astnode.js index 02bfb8bb..26be7ec9 100644 --- a/lib/jsdoc/src/astnode.js +++ b/lib/jsdoc/src/astnode.js @@ -27,13 +27,16 @@ var isScope = exports.isScope = function(node) { var addNodeProperties = exports.addNodeProperties = function(node) { var doop = require('jsdoc/util/doop'); + var debugEnabled = !!global.env.opts.debug; + if (!node || typeof node !== 'object') { return null; } if (!node.nodeId) { Object.defineProperty(node, 'nodeId', { - value: 'astnode' + uid++ + value: 'astnode' + uid++, + enumerable: debugEnabled }); } @@ -77,6 +80,24 @@ var addNodeProperties = exports.addNodeProperties = function(node) { }); } + if (debugEnabled && !node.parentId) { + Object.defineProperty(node, 'parentId', { + enumerable: true, + get: function() { + return this.parent ? this.parent.nodeId : null; + } + }); + } + + if (debugEnabled && !node.enclosingScopeId) { + Object.defineProperty(node, 'enclosingScopeId', { + enumerable: true, + get: function() { + return this.enclosingScope ? this.enclosingScope.nodeId : null; + } + }); + } + return node; }; diff --git a/test/specs/jsdoc/src/astnode.js b/test/specs/jsdoc/src/astnode.js index 737c6f0e..b7aa2741 100644 --- a/test/specs/jsdoc/src/astnode.js +++ b/test/specs/jsdoc/src/astnode.js @@ -1,4 +1,4 @@ -/*global describe: true, env: true, expect: true, it: true */ +/*global afterEach, beforeEach, describe, env, expect, it */ 'use strict'; describe('jsdoc/src/astnode', function() { @@ -247,6 +247,16 @@ describe('jsdoc/src/astnode', function() { }); describe('addNodeProperties', function() { + var debugEnabled; + + beforeEach(function() { + debugEnabled = !!global.env.opts.debug; + }); + + afterEach(function() { + global.env.opts.debug = debugEnabled; + }); + it('should return null for undefined input', function() { expect( astnode.addNodeProperties() ).toBe(null); }); @@ -278,6 +288,17 @@ describe('jsdoc/src/astnode', function() { expect(node.nodeId).toBe(nodeId); }); + it('should add an enumerable nodeId in debug mode', function() { + var descriptor; + var node; + + global.env.opts.debug = true; + node = astnode.addNodeProperties({}); + descriptor = Object.getOwnPropertyDescriptor(node, 'nodeId'); + + expect(descriptor.enumerable).toBe(true); + }); + it('should add a non-enumerable, writable parent if necessary', function() { var node = astnode.addNodeProperties({}); var descriptor = Object.getOwnPropertyDescriptor(node, 'parent'); @@ -301,6 +322,41 @@ describe('jsdoc/src/astnode', function() { expect(node.parent).toBe(null); }); + it('should add an enumerable parentId in debug mode', function() { + var descriptor; + var node; + + global.env.opts.debug = true; + node = astnode.addNodeProperties({}); + descriptor = Object.getOwnPropertyDescriptor(node, 'parentId'); + + expect(descriptor).toBeDefined(); + expect(descriptor.enumerable).toBe(true); + }); + + it('should provide a null parentId in debug mode for nodes with no parent', function() { + var descriptor; + var node; + + global.env.opts.debug = true; + node = astnode.addNodeProperties({}); + + expect(node.parentId).toBe(null); + }); + + it('should provide a non-null parentId in debug mode for nodes with a parent', function() { + var descriptor; + var node; + var parent; + + global.env.opts.debug = true; + node = astnode.addNodeProperties({}); + parent = astnode.addNodeProperties({}); + node.parent = parent; + + expect(node.parentId).toBe(parent.nodeId); + }); + it('should add a non-enumerable, writable enclosingScope if necessary', function() { var node = astnode.addNodeProperties({}); var descriptor = Object.getOwnPropertyDescriptor(node, 'enclosingScope'); @@ -324,6 +380,43 @@ describe('jsdoc/src/astnode', function() { expect(node.enclosingScope).toBe(null); }); + it('should add an enumerable enclosingScopeId in debug mode', function() { + var descriptor; + var node; + + global.env.opts.debug = true; + node = astnode.addNodeProperties({}); + descriptor = Object.getOwnPropertyDescriptor(node, 'enclosingScopeId'); + + expect(descriptor).toBeDefined(); + expect(descriptor.enumerable).toBe(true); + }); + + it('should provide a null enclosingScopeId in debug mode for nodes with no enclosing scope', + function() { + var descriptor; + var node; + + global.env.opts.debug = true; + node = astnode.addNodeProperties({}); + + expect(node.enclosingScopeId).toBe(null); + }); + + it('should provide a non-null enclosingScopeId in debug mode for nodes with an enclosing ' + + 'scope', function() { + var descriptor; + var enclosingScope; + var node; + + global.env.opts.debug = true; + node = astnode.addNodeProperties({}); + enclosingScope = astnode.addNodeProperties({}); + node.enclosingScope = enclosingScope; + + expect(node.enclosingScopeId).toBe(enclosingScope.nodeId); + }); + it('should add a non-enumerable knownVariables property', function() { var node = astnode.addNodeProperties({}); var descriptor = Object.getOwnPropertyDescriptor(node, 'knownVariables');