Inital Commit
This commit is contained in:
commit
f8c7ae5776
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
npm-debug.log
|
||||
8
.jshintrc
Normal file
8
.jshintrc
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"globalstrict": true,
|
||||
"node": true,
|
||||
"undef": true,
|
||||
"indent": 2,
|
||||
"quotmark": "single",
|
||||
"predef": ["describe", "it", "before", "beforeEach", "after", "afterEach"]
|
||||
}
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Zeke Sonxx <github.com/zekesonxx>
|
||||
|
||||
Permission is hereby granted, free of charge, to any pony obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit ponies to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
23
README.md
Normal file
23
README.md
Normal file
@ -0,0 +1,23 @@
|
||||
# wow-toc
|
||||
|
||||
World Of Warcraft addon `.toc` file parser. Written in Node.js.
|
||||
|
||||
Built on the documentation at [Wowpedia](http://wowpedia.org/TOC_format).
|
||||
|
||||
## Usage
|
||||
`$ npm install wow-toc`
|
||||
|
||||
````js
|
||||
var wowtoc = require('wow-toc');
|
||||
|
||||
var k = wowtoc.parse(fs.readFileSync('somefile.toc'));
|
||||
wowtoc.stringify(k);
|
||||
````
|
||||
|
||||
## Notes / Caveats
|
||||
* Does not acknowledge `#@no-lib-strip@`/`#@end-no-lib-strip@`
|
||||
* `Dependencies`/`OptionalDeps`/etc remain strings (easy to convert to arrays anyways)
|
||||
* Doesn't validate tag names (`## Bacon: Strip` is valid to it but not to WoW)
|
||||
|
||||
## License
|
||||
MIT. See `LICENSE`
|
||||
62
lib/index.js
Normal file
62
lib/index.js
Normal file
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* World Of Warcraft Addon .toc file parser
|
||||
* Based on the documentation at http://wowpedia.org/TOC_format
|
||||
* @author Zeke Sonxx <github.com/zekesonxx>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
var debug = require('debug')('wow-toc');
|
||||
|
||||
exports.parse = function(input) {
|
||||
if (typeof input !== 'string') {
|
||||
throw new Error('wowtoc.parse input must be a string, got '+typeof input);
|
||||
}
|
||||
var lines = input.split(/\r*\n/); //allow Windows newlines
|
||||
debug('Got input, '+lines.length+' lines');
|
||||
var out = {
|
||||
tags: {},
|
||||
files: []
|
||||
};
|
||||
lines.forEach(function(line) {
|
||||
if (line.length > 1024) {
|
||||
//WoW only reads the first 1024 lines
|
||||
debug('Line is longer than 1024 characters, trunicating to be like WoW');
|
||||
line = line.substr(0, 1024);
|
||||
}
|
||||
|
||||
if (line.substr(0, 2) === '##') { //## Title: Recount
|
||||
debug('Line is tag: '+line);
|
||||
var tag = line.substr(2, line.indexOf(':')).trim().replace(':', '');
|
||||
var value = line.substr(line.indexOf(':')+1, line.length).trim();
|
||||
debug('`'+tag+'` : `'+value+'`');
|
||||
out.tags[tag] = value;
|
||||
} else if (line.substr(0, 1) === '#') { //#bug not feature
|
||||
debug('Line is comment: '+line);
|
||||
} else { // recount.lua
|
||||
//file loading
|
||||
debug('Line is file: '+line);
|
||||
if (line.trim() !== '') {
|
||||
out.files.push(line.trim());
|
||||
}
|
||||
}
|
||||
});
|
||||
return out;
|
||||
};
|
||||
|
||||
exports.stringify = function(input) {
|
||||
if (typeof input !== 'object') {
|
||||
throw new TypeError('wowtoc.stringify input must be an object, got '+typeof input);
|
||||
}
|
||||
|
||||
var out = [];
|
||||
for(var tag in input.tags) {
|
||||
if(input.tags.hasOwnProperty(tag)) {
|
||||
out.push('## '+tag+': '+input.tags[tag]);
|
||||
}
|
||||
}
|
||||
(input.files || []).forEach(function(file) {
|
||||
out.push(file);
|
||||
});
|
||||
return out.join('\n');
|
||||
};
|
||||
31
package.json
Normal file
31
package.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "wow-toc",
|
||||
"version": "0.1.0",
|
||||
"description": "World Of Warcraft addon toc file parser",
|
||||
"main": "lib/index.js",
|
||||
"scripts": {
|
||||
"test": "node node_modules/mocha/bin/_mocha -R spec"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zekesonxx/wow-toc"
|
||||
},
|
||||
"keywords": [
|
||||
"wow",
|
||||
"toc",
|
||||
"parser"
|
||||
],
|
||||
"author": "Zeke Sonxx <github.com/zekesonxx>",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/zekesonxx/wow-toc/issues"
|
||||
},
|
||||
"homepage": "https://github.com/zekesonxx/wow-toc",
|
||||
"dependencies": {
|
||||
"debug": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha": "^1.21.4",
|
||||
"should": "^4.0.4"
|
||||
}
|
||||
}
|
||||
58
test/fixtures/Recount.json
vendored
Normal file
58
test/fixtures/Recount.json
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
{
|
||||
"files" : [
|
||||
"embeds.xml",
|
||||
"locales\\Recount-enUS.lua",
|
||||
"locales\\Recount-deDE.lua",
|
||||
"locales\\Recount-esES.lua",
|
||||
"locales\\Recount-esMX.lua",
|
||||
"locales\\Recount-frFR.lua",
|
||||
"locales\\Recount-ptBR.lua",
|
||||
"locales\\Recount-ruRU.lua",
|
||||
"locales\\Recount-koKR.lua",
|
||||
"locales\\Recount-zhTW.lua",
|
||||
"locales\\Recount-zhCN.lua",
|
||||
"Recount.lua",
|
||||
"Fonts.lua",
|
||||
"colors.lua",
|
||||
"Widgets.lua",
|
||||
"WindowOrder.lua",
|
||||
"Fights.lua",
|
||||
"Recount_Modes.lua",
|
||||
"TrackerModules\\TrackerModule_Dispels.lua",
|
||||
"TrackerModules\\TrackerModule_Interrupts.lua",
|
||||
"TrackerModules\\TrackerModule_Resurrection.lua",
|
||||
"TrackerModules\\TrackerModule_CCBreakers.lua",
|
||||
"TrackerModules\\TrackerModule_PowerGains.lua",
|
||||
"Tracker.lua",
|
||||
"roster.lua",
|
||||
"LazySync.lua",
|
||||
"deletion.lua",
|
||||
"zonefilters.lua",
|
||||
"debug.lua",
|
||||
"GUI_Main.lua",
|
||||
"GUI_Detail.lua",
|
||||
"GUI_DeathGraph.lua",
|
||||
"GUI_Graph.lua",
|
||||
"GUI_Reset.lua",
|
||||
"GUI_Report.lua",
|
||||
"GUI_Config.lua",
|
||||
"GUI_Realtime.lua"
|
||||
],
|
||||
"tags" : {
|
||||
"Author" : "Cryect, ported to 2.4 by Elsia, maintained by Resike from 5.4",
|
||||
"Interface" : "50400",
|
||||
"Notes" : "Records Damage and Healing for Graph Based Display.",
|
||||
"Notes-ruRU" : "Записывает урон и исцеления и отоброжает различные графики.",
|
||||
"Notes-zhCN" : "基于 Graph 裤开发的伤害/治疗统计插件.",
|
||||
"Notes-zhTW" : "圖形化顯示的傷害/治療統計插件.",
|
||||
"OptionalDeps" : "Ace3, LibDropdown-1.0, LibSharedMedia-3.0, LibBossIDs-1.0, LibGraph-2.0",
|
||||
"SavedVariables" : "RecountDB",
|
||||
"SavedVariablesPerCharacter" : "RecountPerCharDB",
|
||||
"Title" : "Recount",
|
||||
"Version" : "r1269",
|
||||
"X-Curse-Packaged-Version" : "r1269",
|
||||
"X-Curse-Project-ID" : "recount",
|
||||
"X-Curse-Project-Name" : "Recount",
|
||||
"X-Curse-Repository-ID" : "wow/recount/mainline"
|
||||
}
|
||||
}
|
||||
60
test/fixtures/Recount.toc
vendored
Normal file
60
test/fixtures/Recount.toc
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
## Interface: 50400
|
||||
## Version: r1269
|
||||
## Title: Recount
|
||||
## Notes: Records Damage and Healing for Graph Based Display.
|
||||
## Notes-ruRU: Записывает урон и исцеления и отоброжает различные графики.
|
||||
## Notes-zhCN: 基于 Graph 裤开发的伤害/治疗统计插件.
|
||||
## Notes-zhTW: 圖形化顯示的傷害/治療統計插件.
|
||||
## Author: Cryect, ported to 2.4 by Elsia, maintained by Resike from 5.4
|
||||
## OptionalDeps: Ace3, LibDropdown-1.0, LibSharedMedia-3.0, LibBossIDs-1.0, LibGraph-2.0
|
||||
## SavedVariables: RecountDB
|
||||
## SavedVariablesPerCharacter: RecountPerCharDB
|
||||
## X-Curse-Packaged-Version: r1269
|
||||
## X-Curse-Project-Name: Recount
|
||||
## X-Curse-Project-ID: recount
|
||||
## X-Curse-Repository-ID: wow/recount/mainline
|
||||
|
||||
#@no-lib-strip@
|
||||
embeds.xml
|
||||
#@end-no-lib-strip@
|
||||
|
||||
locales\Recount-enUS.lua
|
||||
locales\Recount-deDE.lua
|
||||
locales\Recount-esES.lua
|
||||
locales\Recount-esMX.lua
|
||||
locales\Recount-frFR.lua
|
||||
locales\Recount-ptBR.lua
|
||||
locales\Recount-ruRU.lua
|
||||
locales\Recount-koKR.lua
|
||||
locales\Recount-zhTW.lua
|
||||
locales\Recount-zhCN.lua
|
||||
|
||||
Recount.lua
|
||||
|
||||
Fonts.lua
|
||||
colors.lua
|
||||
Widgets.lua
|
||||
WindowOrder.lua
|
||||
|
||||
Fights.lua
|
||||
Recount_Modes.lua
|
||||
TrackerModules\TrackerModule_Dispels.lua
|
||||
TrackerModules\TrackerModule_Interrupts.lua
|
||||
TrackerModules\TrackerModule_Resurrection.lua
|
||||
TrackerModules\TrackerModule_CCBreakers.lua
|
||||
TrackerModules\TrackerModule_PowerGains.lua
|
||||
Tracker.lua
|
||||
roster.lua
|
||||
LazySync.lua
|
||||
deletion.lua
|
||||
zonefilters.lua
|
||||
debug.lua
|
||||
|
||||
GUI_Main.lua
|
||||
GUI_Detail.lua
|
||||
GUI_DeathGraph.lua
|
||||
GUI_Graph.lua
|
||||
GUI_Reset.lua
|
||||
GUI_Report.lua
|
||||
GUI_Config.lua
|
||||
GUI_Realtime.lua
|
||||
7
test/fixtures/basic-file.toc
vendored
Normal file
7
test/fixtures/basic-file.toc
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
## Interface: 50400
|
||||
## Title: Waiting for Godot
|
||||
## Notes: "Nothing to be done."
|
||||
## Version: 4.2
|
||||
#Comment
|
||||
Vladimir.xml
|
||||
Estragon.lua
|
||||
6
test/fixtures/basic-output.toc
vendored
Normal file
6
test/fixtures/basic-output.toc
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
## Title: Bacon
|
||||
## Interface: 50400
|
||||
## Notes: I hate everyone
|
||||
## Version: 4.3.2.1
|
||||
load.xml
|
||||
bacon.lua
|
||||
3
test/fixtures/trunicate.toc
vendored
Normal file
3
test/fixtures/trunicate.toc
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
## Title: Trunicate Me
|
||||
## X-Long: dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
|
||||
somefile.lua
|
||||
75
test/parse_spec.js
Normal file
75
test/parse_spec.js
Normal file
@ -0,0 +1,75 @@
|
||||
'use strict';
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var should = require('should');
|
||||
var wowtoc = require('../lib');
|
||||
|
||||
describe('wow-toc.parse', function() {
|
||||
it ('should work on a basic file', function () {
|
||||
var fixture = fs.readFileSync(path.join(__dirname, 'fixtures', 'basic-file.toc'), { encoding: 'utf8' });
|
||||
wowtoc.parse(fixture).should.eql({
|
||||
tags: {
|
||||
'Interface': '50400',
|
||||
'Title': 'Waiting for Godot',
|
||||
'Notes': '"Nothing to be done."',
|
||||
'Version': '4.2'
|
||||
},
|
||||
files: [
|
||||
'Vladimir.xml',
|
||||
'Estragon.lua'
|
||||
]
|
||||
});
|
||||
});
|
||||
it ('should trunicate lines over 1024', function() {
|
||||
var fixture = fs.readFileSync(path.join(__dirname, 'fixtures', 'trunicate.toc'), { encoding: 'utf8' });
|
||||
wowtoc.parse(fixture).tags['X-Long'].should.equal('d'.repeat(1024-11));
|
||||
});
|
||||
it ('should correctly parse Recount.toc', function() {
|
||||
/**
|
||||
* Recount was selected because it's well known has a fairly large toc,
|
||||
* and it has non-latin characters in some translations.
|
||||
* I can't find any data on the Recount license, so I'm attributing it
|
||||
* and leaving it unmodified in test/fixtures/Recount.toc
|
||||
*/
|
||||
var fixture = fs.readFileSync(path.join(__dirname, 'fixtures', 'Recount.toc'), { encoding: 'utf8' });
|
||||
var correct = fs.readFileSync(path.join(__dirname, 'fixtures', 'Recount.json'), { encoding: 'utf8' });
|
||||
wowtoc.parse(fixture).should.eql(JSON.parse(correct));
|
||||
});
|
||||
});
|
||||
|
||||
//polyfill from MDN
|
||||
if (!String.prototype.repeat) {
|
||||
// jshint ignore:start
|
||||
String.prototype.repeat = function (count) {
|
||||
"use strict";
|
||||
if (this == null)
|
||||
throw new TypeError("can't convert " + this + " to object");
|
||||
var str = "" + this;
|
||||
count = +count;
|
||||
if (count != count)
|
||||
count = 0;
|
||||
if (count < 0)
|
||||
throw new RangeError("repeat count must be non-negative");
|
||||
if (count == Infinity)
|
||||
throw new RangeError("repeat count must be less than infinity");
|
||||
count = Math.floor(count);
|
||||
if (str.length == 0 || count == 0)
|
||||
return "";
|
||||
// Ensuring count is a 31-bit integer allows us to heavily optimize the
|
||||
// main part. But anyway, most current (august 2014) browsers can't handle
|
||||
// strings 1 << 28 chars or longer, so :
|
||||
if (str.length * count >= 1 << 28)
|
||||
throw new RangeError("repeat count must not overflow maximum string size");
|
||||
var rpt = "";
|
||||
for (;;) {
|
||||
if ((count & 1) == 1)
|
||||
rpt += str;
|
||||
count >>>= 1;
|
||||
if (count == 0)
|
||||
break;
|
||||
str += str;
|
||||
}
|
||||
return rpt;
|
||||
}
|
||||
// jshint ignore:end
|
||||
}
|
||||
20
test/stringify_spec.js
Normal file
20
test/stringify_spec.js
Normal file
@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var should = require('should');
|
||||
var wowtoc = require('../lib');
|
||||
|
||||
describe('wow-toc.stringify', function() {
|
||||
it ('should work with basic data', function() {
|
||||
var fixture = fs.readFileSync(path.join(__dirname, 'fixtures', 'basic-output.toc'), { encoding: 'utf8' });
|
||||
wowtoc.stringify({
|
||||
tags: {
|
||||
'Title': 'Bacon',
|
||||
'Interface': '50400',
|
||||
'Notes': 'I hate everyone',
|
||||
'Version': '4.3.2.1'
|
||||
},
|
||||
files: ['load.xml', 'bacon.lua']
|
||||
}).should.equal(fixture);
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user