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