The javascript interpreter triggerred a SytaxError after i compressed my code, but i don't know the exact position triggered this problem at my code. It's very hard to find out. I tried jsLint aslo, but it can't point out problem aslo.
(function(){var session,start,end,pool={length:0},result=[],id=0;function poolAdd(procedure,expected,description){pool[id+++""]={"description":description||"No description","procedure":procedure,"expected":expected};pool["length"]++;return id-1;}function poolRun(id){var actual,expect,pass,test=pool[id];if(test){try{actual=typeof test.procedure==="function"?test.procedure():test.procedure;expect=typeof test.expected==="function"?test.expected():test.expected;pass=actual===expect;if(pass){test["pass"]=true}else{test["fail"]={"actual":actual,"expect":expect}}}catch(e){test["fail"]={"message":e.toString()}}finally{delete pool[id];pool.length--;return result.push(test)-1;}}return-1;}function percentage(fraction){return!(fraction>=0&&fraction<=1)?"Not available":(fraction*100+"").substr(0,5)+"%"}function Statics(data,session){if(this instanceof Statics){this.data=(data||result).slice(0);if(session){this.session={id:session.id,end:session.end,start:session.start}}}else{return new Statics(data,session)}}Statics.prototype={statics:function(format){var temp,report,passed=[],failed=[];format=format||"text";for(var i=0,l=this.data.length;i<l;i++){temp=this.data[i];if(typeof temp==="number"){temp=result[temp+""]}temp.pass&&passed.push(temp);temp.fail&&failed.push(temp)}if(format==="text"){report=[];report.push("***"+(this.session?" Session("+this.session.id+")":"")+" Test Report ***");report.push(" Cost: "+(this.session?(this.session.end-this.session.start)/1000:(end-start)/1000)+" seconds");report.push(" Total: "+this.data.length);report.push("Passed: "+passed.length);report.push("Failed: "+failed.length);report.push("Percet: "+percentage(passed.length/this.data.length));if(failed.length>0){report.push("Detail:");for(var i=0,l=failed.length;i<l;i++){temp=failed[i];if(temp.fail.message){report.push(i+1+")."+" >>>EXCEPTION THROWN<<< in test("+temp.description+") "+temp.fail.message)}else{report.push(i+1+")."+" >>>VALUE NOT MATCH<<< in test("+temp.description+") "+" expected "+temp.fail.expect+" actual "+temp.fail.actual)}}}return report.join("\n")}}}function session_start(){session=new Session();session.start=+new Date;}function session_end(){session&&(session.end=+new Date)}function session_destory(){session=null}function Session(){this.id=QQWB.uid();this.idPool=[];}Session.prototype={_addId:function(id){this.idPool.push(id)},add:function(procedure,expected,description){this._addId(poolAdd(procedure,expected,description));return this},run:function(){var temp,statics,results=[];for(var i=0,l=this.idPool.length;i<l;i++){temp=poolRun(this.idPool[i]);temp&&results.push(temp)}session_end();statics=Statics(results,session);session_destory();return statics}};QQWB.extend("test",{add:function(procedure,expected,description){session_start();session._addId(poolAdd(procedure,expected,description));return session},run:function(){session_destory();start=+new Date;for(var id in pool){if(id!=='length'&&pool.hasOwnProperty(id)){poolRun(id)}}end=+new Date;return Statics()},remains:function(){return pool.length}})}());
added my original code
(function (){
var
session, // test session
start, // start time of call test.run()
end, // end time of test.run()
pool = {length:0}, // pool of all the tests removed from pool when test done
result = [], // pool of the result of test
id = 0; // test unique id auto increment
/**
* Add a test item to pool
*
* #access private
* #return {Number} the index in the pool
*/
function poolAdd(procedure, expected, description) {
pool[id+++""] = {
"description": description || "No description"
,"procedure": procedure
,"expected": expected
};
pool["length"]++; // maintain the length property of pool
return id - 1; // id of current test
}
/**
* Run a test
*
* Test item will be marked as pass or fail then move from
* test's pool to result's pool
*
* #access private
* #param id {Number} the index in the test pool
* #return {Number} the index in the result pool
*/
function poolRun(id) {
var
actual, // actual value
expect, // expected value
pass, // indicate test whether passed
test = pool[id]; // the test object
if (test) {
try{
actual = typeof test.procedure === "function" ? test.procedure() : test.procedure; // run test procedure
expect = typeof test.expected === "function" ? test.expected() : test.expected; // run expect procedure
pass = actual === expect;
if (pass) {
test["pass"] = true;
} else {
test["fail"] = {
"actual": actual
,"expect": expect
}
}
} catch (e) {
test["fail"] = {
"message": e.toString()
}
} finally {
delete pool[id]; // remove from pool
pool.length--; // maintain the length property of pool
return result.push(test) - 1; // the index in the result array for current test item
}
}
return -1; // id not valid
}
/**
* Float to percentage string
*
* #access private
* #param fraction {Number} float number
* #return {String} percentage string
*/
function percentage (fraction) {
return !(fraction >= 0 && fraction <= 1) ? "Not available" : (fraction * 100 + "").substr(0,5) + "%";
}
/**
* Statics constructor
*
* Self invoke constructor
*
* Note:
* If data is passed in,it means the statics running in a session
* Data contains *position* of result pool
*
* #access private
* #param data {Array} partial result keys array or the result
* #return {Statics} a statics instance
*/
function Statics(data, session) {
if (this instanceof Statics) {
this.data = (data || result).slice(0); // clone array
if (session) {
this.session = {
id: session.id
,end: session.end
,start: session.start
};
}
} else {
return new Statics(data, session);
}
}
Statics.prototype = {
/**
* Get statics
*
* Currently only support text statics
*
* #access public
* #param format {String} text,xml,json etc.
* #return {Mixed} result statics
*/
statics: function (format) {
var
temp, // temp value
report, // statics report
passed = [], // passed tests pool
failed = []; // failed tests pool
format = format || "text"; // default report type is text
for (var i=0,l=this.data.length; i<l; i++) {
temp = this.data[i];
if (typeof temp === "number") { // convert key to its value
temp = result[temp+""];
}
temp.pass && passed.push(temp);
temp.fail && failed.push(temp);
}
if (format === "text") {
report = [];
report.push("***" + (this.session ? " Session(" + this.session.id +")":"") + " Test Report ***");
report.push(" Cost: " + (this.session ? (this.session.end - this.session.start)/1000 : (end - start)/1000) + " seconds");
report.push(" Total: " + this.data.length);
report.push("Passed: " + passed.length);
report.push("Failed: " + failed.length);
report.push("Percet: " + percentage(passed.length/this.data.length));
if (failed.length > 0) {
report.push("Detail:");
for (var i=0,l=failed.length; i<l; i++) {
temp = failed[i];
if (temp.fail.message) {
report.push( i + 1 + ")." + " >>>EXCEPTION THROWN<<< in test(" + temp.description + ") " + temp.fail.message);
} else {
report.push( i + 1 + ")." + " >>>VALUE NOT MATCH<<< in test(" + temp.description + ") " + " expected " + temp.fail.expect + " actual " + temp.fail.actual);
}
}
}
return report.join("\n");
}
}
}
/**
* Start a new test session
*
* #access private
* #return {Void}
*/
function session_start() {
// if checked T.test.add(...); T.test.add(...); will be treated as one session till run is called
// if (!session) {
session = new Session();
session.start = + new Date;
// }
}
/**
* End current session
*
* #access private
* #return {Void}
*/
function session_end() {
session && (session.end = + new Date);
}
/**
* Destory current session
*
* #access private
* #return {Void}
*/
function session_destory() {
session = null;
}
/**
* Session constructor
*
* #access private
* #return {Session} session instance
*/
function Session() {
this.id = QQWB.uid(); // random session id
this.idPool = []; // contains id of test
}
Session.prototype = {
/**
* Add test id to session
*
* #access private
* #param id {Number} test id
* #return {Void}
*/
_addId: function (id) {
this.idPool.push(id);
}
/**
* Add test item to session
*
* Note:
* Test item added to global pool
* Session just store the position of test in the pool
*
* Example usage:
* T.test
* .add(...) //add a test to session(and pool)
* .add(...) //add a test to session(and pool)
* ...
*
*
* #access public
* #param procedure {Mixed} the procedure to finish this test
* if procedure is a function it will
* be executed automaticlly
* #param expected {Mixed} the expected value of this test
* if expected is a function it will
* be executed automaticlly
* #param description {String} speak more about this test
* #return {Session} the current session
*/
,add: function (procedure, expected, description) {
this._addId(poolAdd(procedure, expected, description));
return this;
}
/**
* Run the tests in current session
*
* Example usage:
* T.test
* .add(...) //add a test to session(and pool)
* .add(...) //add a test to session(and pool)
* ...
* .run() // run the test in this session
* .statics() // get statics for this session
*
* #access public
* #return {Statics} statics object
*/
,run: function () { // run in session
var temp,
statics,
results = [];
for (var i=0,l=this.idPool.length; i<l; i++) {
temp = poolRun(this.idPool[i]);
temp && results.push(temp);
}
session_end(); // record the time of this session end
statics = Statics(results,session);
session_destory();// destory test session
return statics;
}
};
QQWB.extend("test",{
/**
* Add test item to session
*
* Note:
* Test item added to global pool
* Current session will store the position of test in the pool
*
* Example usage:
* T.test
* .add(...) //add a test to session(and pool)
* .add(...) //add a test to session(and pool)
* ...
*
* #access public
* #param procedure {Mixed} the procedure to finish this test
* if procedure is a function it will
* be executed automaticlly
* #param expected {Mixed} the expected value of this test
* if expected is a function it will
* be executed automaticlly
* #param description {String} speak more about this test
* #return {Session} the current session
*/
add: function (procedure, expected, description) {
session_start(); // spawn a new session object
session._addId(poolAdd(procedure, expected, description));
return session;
}
/**
* Run all the tests except the test already done
*
* Example usage:
* T.test
* .add(...) //add a test to session(and pool)
* .add(...) //add a test to session(and pool)
* ...
*
* T.test
* .run() // run all the tests except already done
* .statics() //get full statics of all the tests
*
* #access public
* #return {Statics} statics object
*/
,run: function () {
session_destory(); // destory current session
start = + new Date; // start time of global test
for (var id in pool) {
if (id !== 'length' && pool.hasOwnProperty(id)) {
poolRun(id);
}
}
end = + new Date; // end time of global test
return Statics();
}
/**
* Get count of tests left in the pool
*
* #access public
* #return {Number} count of tests unfinished yet
*/
,remains: function () {
return pool.length;
}
});
}());
This is the script packer
http://dean.edwards.name/packer/
Edited:
I solved this problem by myself finally,I paste the code piece by piece to the packer. finally find out that the defination of Statics.prototype isn't end with a semicolon which caused SytaxError.
I tried copying the javascript to http://jsfiddle.net/ then clicking JSLint - gave me all sorts of errors.
What tool are you using for the compression?
My guess is missing semicolons.
For example:
test["fail"] = {
"message": e.toString()
}
Should have a semicolon after the closing brace.
Related
I have a js function:
/**
*
* #param {Object} obj function gets on param - an object
* #param {Number} obj.param1 - 1st num
* #param {Number} obj.param2 - 2nd num
*
* #returns {Number} - the result of the request
*/
const myFunc = ({ param1, param2 }) => {
return param1 * param2
}
After compiling it with babel I get:
/**
*
* #param {Object} obj function gets on param - an object
* #param {Number} obj.param1 - 1st num
* #param {Number} obj.param2 - 2nd num
*
* #returns {Number} - the result of the request
*/
var myFunc = (_ref) => {
var param1 = _ref.param1,
param2 = _ref.param2
return param1 * param2
}
At this point jsdoc is breaking because it is not connecting the jsdoc declaration to the function below anymore.
I also tried to use #function with #name but still no success.
I want to be able to see the relevant param type and comment when using the compiled version. Any idea how can I keep it consistent?
Thanks
I'm doing a coding challenge and I'm having difficulty returning anything besides undefined. Instead of true or false from the function defined after
Logger.prototype.shouldPrintMessage = function(timestamp, message)
I use MD5 Hashing to match if an exact message has been sent prior.
It's probably something obvious but I don't have enough experience with class/constructor functions.
You need to copy and paste the MD5 Hash function to the top of the code for it to work. You can find it in the first comment of this code.
// MD5 Hash
// Taken from : http://www.myersdaily.org/joseph/javascript/md5-text.html
// Paste Here
/**
* Initialize your data structure here.
*/
var Logger = function() {
this.messageStore = {}
};
/**
* Returns true if the message should be printed in the given timestamp, otherwise returns false.
If this method returns false, the message will not be printed.
The timestamp is in seconds granularity.
* #param {number} timestamp
* #param {string} message
* #return {boolean}
*/
Logger.prototype.shouldPrintMessage = function(timestamp, message) {
let hashedMessage = md5(message);
if (!(hashedMessage in this.messageStore)){
this.messageStore[message] = timestamp;
} else if ((timestamp - this.messageStore.hashedMessage) > 9) {
return true;
}
else if ((timestamp - this.messageStore.hashedMessage) < 10) {
return false;
}
else {
return undefined;
}
};
/**
* Your Logger object will be instantiated and called as such:
* var obj = new Logger()
* var param_1 = obj.shouldPrintMessage(timestamp,message)
*/
var obj = new Logger();
console.log(obj.shouldPrintMessage(1,"foo"));
console.log(obj.shouldPrintMessage(2,"bar"));
console.log(obj.shouldPrintMessage(3,"foo"));
console.log(obj.shouldPrintMessage(8,"bar"));
console.log(obj.shouldPrintMessage(10,"foo"));
console.log(obj.shouldPrintMessage(11,"foo"));
You need to do this.messageStore[hashedMessage] = timestamp; since that is what you are storing it as, and then anywhere you do this.messageStore.hashedMessage you need to do this.messageStore[hashedMessage']:
// MD5 Hash
// Taken from : http://www.myersdaily.org/joseph/javascript/md5-text.html
// Paste Here
md5 = window.btoa;
/**
* Initialize your data structure here.
*/
var Logger = function() {
this.messageStore = {}
};
/**
* Returns true if the message should be printed in the given timestamp, otherwise returns false.
If this method returns false, the message will not be printed.
The timestamp is in seconds granularity.
* #param {number} timestamp
* #param {string} message
* #return {boolean}
*/
Logger.prototype.shouldPrintMessage = function(timestamp, message) {
let hashedMessage = md5(message);
if (!(hashedMessage in this.messageStore)){
this.messageStore[hashedMessage] = timestamp;
return;
} else if ((timestamp - this.messageStore[hashedMessage]) > 9) {
return true;
}
else if ((timestamp - this.messageStore[hashedMessage]) < 10) {
return false;
}
};
/**
* Your Logger object will be instantiated and called as such:
* var obj = new Logger()
* var param_1 = obj.shouldPrintMessage(timestamp,message)
*/
var obj = new Logger();
console.log(obj.shouldPrintMessage(1,"foo"));
console.log(obj.shouldPrintMessage(2,"bar"));
console.log(obj.shouldPrintMessage(3,"foo"));
console.log(obj.shouldPrintMessage(8,"bar"));
console.log(obj.shouldPrintMessage(10,"foo"));
console.log(obj.shouldPrintMessage(11,"foo"));
I do have following Errors when js file is minified
/* Minification failed. Returning unminified contents.
(36307,7-8): run-time error JS1010: Expected identifier: .
(36307,7-8): run-time error JS1195: Expected expression: .
(36817,7-8): run-time error JS1010: Expected identifier: .
(36817,7-8): run-time error JS1195: Expected expression: .
(36820,7-8): run-time error JS1010: Expected identifier: .
(36820,7-8): run-time error JS1195: Expected expression: .
*/
The JavaScript file script file below,
However I found the JavaScript that contains "module.export"
will not be minified and I also use
online tool
for minification, but the minified file does not contain "module.export"
and it is removed
during minification. Any help how to sort the minification problem of JavaScript file contain module.export
(function e(t, n, r) {
module.exports = FilterCSS;
}, {
"./default": 7,
"./parser": 9,
"./util": 10
}], 7: [function(require, module, exports) {
/**
* cssfilter
*
* #author ??<leizongmin#gmail.com>
*/
function getDefaultWhiteList() {
// ??????:
// true: ?????
// Function: function (val) { } ??true???????,?????????
// RegExp: regexp.test(val) ??true???????,?????????
// ??????????????
var whiteList = {};
whiteList['align-content'] = false; // default: auto
whiteList['align-items'] = false; // default: auto
*
*
#param {
String
}
name
*
#param {
String
}
value
*
#param {
Object
}
options
*
#return {
String
}
*/
function onAttr(name, value, options) {
// do nothing
}
/**
* ???????????????
*
* #param {String} name
* #param {String} value
* #param {Object} options
* #return {String}
*/
function onIgnoreAttr(name, value, options) {
// do nothing
}
var REGEXP_URL_JAVASCRIPT = /javascript\s*\:/img;
/**
* ?????
*
* #param {String} name
* #param {String} value
* #return {String}
*/
function safeAttrValue(name, value) {
if (REGEXP_URL_JAVASCRIPT.test(value)) return '';
return value;
}
exports.whiteList = getDefaultWhiteList();
exports.getDefaultWhiteList = getDefaultWhiteList;
exports.onAttr = onAttr;
exports.onIgnoreAttr = onIgnoreAttr;
exports.safeAttrValue = safeAttrValue;
}, {}], 8: [function(require, module, exports) {
/**
* cssfilter
*
* #author ??<leizongmin#gmail.com>
*/
var DEFAULT = require('./default');
var FilterCSS = require('./css');
/**
* XSS??
*
* #param {String} css ????CSS??
* #param {Object} options ??:whiteList, onAttr, onIgnoreAttr
* #return {String}
*/
function filterCSS(html, options) {
var xss = new FilterCSS(options);
return xss.process(html);
}
// ??
exports = module.exports = filterCSS;
exports.FilterCSS = FilterCSS;
for (var i in DEFAULT) exports[i] = DEFAULT[i];
// ???????
if (typeof window !== 'undefined') {
window.filterCSS = module.exports;
}
}, {
"./css": 6,
"./default": 7
}], 9: [function(require, module, exports) {
/**
* cssfilter
*
* #author ??<leizongmin#gmail.com>
*/
var _ = require('./util');
Try like this:
['module'].exports = FilterCSS;
Also this:
[module].exports = FilterCSS;
It worked for me, but no idea why.
Before this epiphany, I had solve similar issues with global variables, using something like this:
window['module'].exports=......
But, at least in my case, module was no global.
No idea how I came up with this, and less idea how it worked. I'm new with javascript.
Resume: I'm currently writting an ActionScript 3 lexer that transforms a source code into tokens. I chosen to interpret the input, a String with optional surrogate pairs wrapped in a class UString, by code points. Under the hood I cache the last read position by using the UStringPos class.
I've tested how it scans the identifier "huehuehue" with...
'use strict';
import {Lexer} from 'core/Lexer';
import {UString} from 'utils/UString';
import ErrorHandler from 'core/ErrorHandler';
const errorHandler = new ErrorHandler(true);
// Tell the length to the `Lexer` manually.
const lexer = new Lexer(
new UString('huehuehue'), 9, errorHandler);
// Scan first token
lexer.next();
const id = lexer.lookahead.value;
console.log(
id,
id.length
);
It should have logged "huehuehue", 9, but was another story...
Why is it missing the last 'e'? The innermost method related on scanning this is Lexer#getCommonIdentifier. I've already tested my UString part and it works okay, by the way.
Lexer Related Definitions
/*
* Class that turns AS3 code into tokens.
*/
export class Lexer
{
/*
* #param {UString} source
* #param {Number} length
* #param {ErrorHandler} errorHandler
*/
constructor(source, length, errorHandler)
{
this.source = source;
this.length = length;
this.index = 0;
this.lineStart = 0;
this.lineNumber = 1;
this.comments = [];
this.errorHandler = errorHandler;
this.previousToken = null;
this.token = null;
this.lookahead = null;
this._special = [];
}
/*
* Verifies the end of file.
*/
eof()
{
return this.index >= this.length;
}
/*
* Advance the previous, current and lookahead tokens.
* The lexer however does not depend on these tokens.
*/
next()
{
this.previousToken = this.token;
this.token = this.lookahead;
this.lookahead = this.lex();
}
/*
* Consumes the next token and return it.
*/
lex()
{
this.consumeWhiteSpaces();
while (this.consumeComment())
this.consumeWhiteSpaces();
let cp = this.source.codePointAt(this.index);
let pureIdentifier =
Character.isIdentifierStart(cp);
if (pureIdentifier || (cp === 0x5C))
return this.scanIdentifierOrKeyword(!pureIdentifier);
if (this.eof())
{
let loc = [ this.index, this.lineNumber ];
return new Token(TokenType.EOF, loc, loc, '<end>');
}
}
/*
* Scan an identifier, keyword or boolean literal.
*/
scanIdentifierOrKeyword(usingEscape)
{
const start = this.index;
let id;
/* Like Esprima does: only identifiers containing
* escapes need some overheads. */
if (usingEscape)
{
id = this.getEscapedIdentifier(
String.fromCodePoint(this.scanUnicodeEscapeSequence()));
}
else
id = this.getCommonIdentifier();
return new Token(
TokenType.IDENTIFIER,
[ start , this.lineNumber ],
[ this.index, this.lineNumber ],
id
);
}
/*
* Interprets an identifier. If any escape appears, switches to
* getEscapedIdentifier().
*/
getCommonIdentifier()
{
const start = this.source.position.offset;
let cp = 0;
// Jump the starting symbol.
++this.index;
while (!this.eof())
{
cp = this.source.codePointAt(this.index);
if (Character.isIdentifierPart(cp))
++this.index;
// Switches to escape-minded task...
else if (cp === 0x5C)
return this.getUnicodeEscapedIdentifier(
this.source.string.slice(
start, this.source.position.offset
)
);
else break;
}
return this.source.string.slice(
start, this.source.position.offset
);
}
/* ... */
}
utils/UString.js
'use strict';
/*
* String wrapper with methods _based_ on code points.
*/
export class UString
{
/*
* Constructs the {UString}.
*
* #param {String} s String to be wrapped.
*/
constructor(s)
{
/*
* #type {String}
*/
this.string = s;
/*
* Tracks the last accessed position.
*
* #type {UStringPos}
*/
this.position = new UStringPos(0, 0);
}
/*
* Reads a code point at specific index.
*
* #param {Number} index
* #return {Number}
*/
codePointAt(index)
{
this.position.walk(this.string, index);
return this.string.codePointAt(this.position.offset);
}
/*
* Slices the internal string by code point indices.
*
* #param {Number} i
* #param {Number} j
* #return {String}
*/
slice(i, j)
{
this.position.walk(this.string, i);
i = this.position.offset;
this.position.walk(this.string, j);
j = this.position.offset;
return this.string.slice(i, j);
}
};
/*
* Class that tracks the position of a code point on a string.
*/
export class UStringPos
{
/*
* Constructs the {UStringPos}.
*
* #param {Number} index The initial index.
* #param {Number} offset The initial offset.
*/
constructor(index, offset)
{
/*
* #type {Number}
*/
this.index = index;
/*
* #type {Number}
*/
this.offset = offset;
}
/*
* Walks to the given index.
*
* #param {String} s
* #param {Number} index
* #note No backward. Track the previous position instead.
* #return {void}
*/
walk(s, index)
{
for (; this.index < index; ++this.index)
this.offset += (
this._usingSurrogates(
s.charCodeAt(this.offset)
) ? 2 : 1
);
}
/*
* #private
*/
_usingSurrogates(ch)
{
return (ch >= 0xD800) && (ch <= 0xDBFF);
}
};
Anything?
Okay. So it was a problem with this.source.position.offset: when I do ++this.index, the offset of my UStringPos doesn't update. The problem was with the slice thing.
this.source.string.slice(
start, this.source.position.offset
);
This slice was based on offsets, since I had to track the previous offset where the identifier started.
Solution
I can use the slice of my own UString class and use the first parameter as an offset and the last one as a normal index.
'use strict';
export class UString
{
// ...
/*
* Slices the internal string by using a pair of
* offset and code point indices.
*
* #param {Number} i Offset
* #param {Number} j
* #return {String}
*/
slice(i, j)
{
this.position.walk(this.string, j);
j = this.position.offset;
return this.string.slice(i, j);
}
};
I've copied an example from here. Below is the example code, but the problem is that Store.TAX_RATE shows up in the documentation as a property of Item and not as a property of the module Store. Any suggestions why ?
Example code:
/**
* This module contains classes for running a store.
* #module Store
*/
var Store = Store || {};
/**
* `TAX_RATE` is stored as a percentage. Value is 13.
* #property TAX_RATE
* #static
* #final
* #type Number
*/
Store.TAX_RATE = 13;
/**
* #class Item
* #constructor
* #param name {String} Item name
* #param price {Number} Item price
* #param quantity {Number} Item quantity (the number available to buy)
*/
Store.Item = function (name, price, quantity) {
/**
* #property name
* #type String
*/
this.name = name;
/**
* #property price
* #type String
*/
this.price = price * 100;
/**
* #property quantity
* #type Number
*/
this.quantity = quantity;
/**
* #property id
* #type Number
*/
this.id = Store.Item._id++;
Store.Item.list[this.id] = this;
};
That's because according to YUIDoc terminology a module is just a collection of related classes, so it can't contain anything but classes.
What you could do instead is to document Store and Store.Item both as classes:
/**
* This module contains classes for running a store.
* #class Store
*/
var Store = Store || {};
/**
* `TAX_RATE` is stored as a percentage. Value is 13.
* #property TAX_RATE
* #type Number
*/
Store.TAX_RATE = 13;
/**
* #class Store.Item
*/
Store.Item = function (name, price, quantity) {
};