Refactor out Emscripten version and restructure
This commit is contained in:
parent
7bdefd916a
commit
277ea3303c
|
@ -1,3 +1,2 @@
|
||||||
/out/
|
/out/
|
||||||
/docs/
|
/docs/
|
||||||
node_modules/
|
|
||||||
|
|
15
README.md
15
README.md
|
@ -1,8 +1,15 @@
|
||||||
# hyperbuild
|
# hyperbuild
|
||||||
|
|
||||||
A fast HTML minifier written in C.
|
A fast HTML minifier written in C, heavily influenced by [kangax's html-minifier](https://github.com/kangax/html-minifier).
|
||||||
Designed to be used in C projects, as an executable, and in Node.js thanks to Emscripten.
|
|
||||||
Minifier heavily influenced by [kangax's html-minifier](https://github.com/kangax/html-minifier).
|
Available in different flavours:
|
||||||
|
|
||||||
|
- Standalone 64-bit Linux executable (this)
|
||||||
|
- [Node.js](https://github.com/wilsonzlin/hyperbuild-nodejs)
|
||||||
|
- [Express](https://github.com/wilsonzlin/hyperbuild-express)
|
||||||
|
- [Webpack](https://github.com/wilsonzlin/hyperbuild-webpack)
|
||||||
|
- [Apache](https://github.com/wilsonzlin/hyperbuild-apache)
|
||||||
|
- [Nginx](https://github.com/wilsonzlin/hyperbuild-nginx)
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
@ -12,7 +19,7 @@ hyperbuild minifies as it parses, directly streaming processed HTML to the outpu
|
||||||
|
|
||||||
### Super fast
|
### Super fast
|
||||||
|
|
||||||
hyperbuild is written in C, and can be run on Node.js using Emscripten, which generates fast Wasm code.
|
hyperbuild is written in C, and uses technologies like Emscripten and Cython to preserve performance in higher-level languages.
|
||||||
|
|
||||||
### Smart whitespace handling
|
### Smart whitespace handling
|
||||||
|
|
||||||
|
|
60
package.json
60
package.json
|
@ -1,60 +0,0 @@
|
||||||
{
|
|
||||||
"name": "hyperbuild",
|
|
||||||
"version": "0.0.3",
|
|
||||||
"description": "Streaming HTML minifier written in C and Emscripten for Node.js",
|
|
||||||
"types": "out/main.d.js",
|
|
||||||
"main": "out/hyperbuild.em.js",
|
|
||||||
"files": [
|
|
||||||
"out/hyperbuild.em.js",
|
|
||||||
"out/hyperbuild.em.wasm",
|
|
||||||
"out/main.d.ts"
|
|
||||||
],
|
|
||||||
"scripts": {
|
|
||||||
"clean": "rm -rf tmp out",
|
|
||||||
"preprocess": "./preprocess.sh",
|
|
||||||
"build": "npm run clean && ./compile.sh",
|
|
||||||
"buildDebug": "npm run clean && ./compile.sh --debug",
|
|
||||||
"buildInternalDocs": "npm run preprocess && doxygen Doxyfile",
|
|
||||||
"test": "mocha out/test/**/*.spec.js",
|
|
||||||
"prepublishOnly": "npm run test && npm run build"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/wilsonzlin/hyperbuild.git"
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"html",
|
|
||||||
"c",
|
|
||||||
"fast",
|
|
||||||
"build",
|
|
||||||
"builder",
|
|
||||||
"preprocess",
|
|
||||||
"preprocessor",
|
|
||||||
"minify",
|
|
||||||
"minifier"
|
|
||||||
],
|
|
||||||
"author": {
|
|
||||||
"email": "contact@wilsonl.in",
|
|
||||||
"name": "Wilson Lin",
|
|
||||||
"url": "https://wilsonl.in/"
|
|
||||||
},
|
|
||||||
"license": "MIT",
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/wilsonzlin/hyperbuild/issues"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/wilsonzlin/hyperbuild#readme",
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/chai": "^4.1.3",
|
|
||||||
"@types/emscripten": "0.0.31",
|
|
||||||
"@types/fs-extra": "^5.0.4",
|
|
||||||
"@types/mocha": "^5.2.1",
|
|
||||||
"@types/node": "^10.5.6",
|
|
||||||
"@types/strip-ansi": "^3.0.0",
|
|
||||||
"chai": "^4.1.2",
|
|
||||||
"fs-extra": "7.0.0",
|
|
||||||
"mocha": "^5.2.0",
|
|
||||||
"strip-ansi": "^4.0.0",
|
|
||||||
"ts-node": "^6.1.0",
|
|
||||||
"typescript": "3.0.1"
|
|
||||||
}
|
|
||||||
}
|
|
191
src/main/c/em.c
191
src/main/c/em.c
|
@ -1,191 +0,0 @@
|
||||||
#include "./stream/content/html.c"
|
|
||||||
#include "./__main__.c"
|
|
||||||
|
|
||||||
void em_init(void) {
|
|
||||||
hb_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
hbe_err_t em_entry(
|
|
||||||
// Can be NULL
|
|
||||||
char *input_code,
|
|
||||||
size_t input_code_length,
|
|
||||||
|
|
||||||
// Can be NULL
|
|
||||||
char *input_path,
|
|
||||||
|
|
||||||
// Can be NULL
|
|
||||||
char **output_code,
|
|
||||||
// Can be NULL
|
|
||||||
size_t *output_code_length,
|
|
||||||
|
|
||||||
// Can be NULL
|
|
||||||
char *output_path,
|
|
||||||
|
|
||||||
int config_keep,
|
|
||||||
int config_buffer,
|
|
||||||
|
|
||||||
// Can be NULL
|
|
||||||
char *suppress,
|
|
||||||
|
|
||||||
// Need nondefault_ex_* because NULL is a valid value for ex_*
|
|
||||||
int nondefault_ex_collapse_whitespace,
|
|
||||||
char *ex_collapse_whitespace,
|
|
||||||
int nondefault_ex_destroy_whole_whitespace,
|
|
||||||
char *ex_destroy_whole_whitespace,
|
|
||||||
int nondefault_ex_trim_whitespace,
|
|
||||||
char *ex_trim_whitespace,
|
|
||||||
|
|
||||||
int trim_class_attr,
|
|
||||||
int decode_entities,
|
|
||||||
int min_conditional_comments,
|
|
||||||
int remove_attr_quotes,
|
|
||||||
int remove_comments,
|
|
||||||
int remove_optional_tags,
|
|
||||||
int remove_tag_whitespace
|
|
||||||
) {
|
|
||||||
em_init();
|
|
||||||
|
|
||||||
hbe_err_t err = NULL;
|
|
||||||
hbe_err_t *hbe_err = &err;
|
|
||||||
|
|
||||||
hbu_fstreamin_t input_file = NULL;
|
|
||||||
hbu_list_char_t input_buffer = NULL;
|
|
||||||
|
|
||||||
hbu_fstreamout_t output_file = NULL;
|
|
||||||
hbu_list_char_t output_buffer = NULL;
|
|
||||||
|
|
||||||
hbu_streamoptions_t config_stream = hbu_streamoptions_create();
|
|
||||||
hbu_pipe_t pipe = NULL;
|
|
||||||
|
|
||||||
nh_set_str_t ex_collapse_whitespace_set = NULL;
|
|
||||||
nh_set_str_t ex_destroy_whole_whitespace_set = NULL;
|
|
||||||
nh_set_str_t ex_trim_whitespace_set = NULL;
|
|
||||||
|
|
||||||
if (suppress != NULL) {
|
|
||||||
HBE_CATCH_F(hbu_streamoptions_parse_and_add_errors_to_suppress, config_stream->suppressed_errors, suppress);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nondefault_ex_collapse_whitespace) {
|
|
||||||
ex_collapse_whitespace_set = HBE_CATCH_F(hbu_streamoptions_parse_list_of_tags, ex_collapse_whitespace);
|
|
||||||
config_stream->ex_collapse_whitespace = ex_collapse_whitespace_set;
|
|
||||||
} else {
|
|
||||||
config_stream->ex_collapse_whitespace = hbu_streamoptions_default_ex_collapse_whitespace();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nondefault_ex_destroy_whole_whitespace) {
|
|
||||||
ex_destroy_whole_whitespace_set = HBE_CATCH_F(hbu_streamoptions_parse_list_of_tags, ex_destroy_whole_whitespace);
|
|
||||||
config_stream->ex_destroy_whole_whitespace = ex_destroy_whole_whitespace_set;
|
|
||||||
} else {
|
|
||||||
config_stream->ex_destroy_whole_whitespace = hbu_streamoptions_default_ex_destroy_whole_whitespace();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nondefault_ex_trim_whitespace) {
|
|
||||||
ex_trim_whitespace_set = HBE_CATCH_F(hbu_streamoptions_parse_list_of_tags, ex_trim_whitespace);
|
|
||||||
config_stream->ex_trim_whitespace = ex_trim_whitespace_set;
|
|
||||||
} else {
|
|
||||||
config_stream->ex_trim_whitespace = hbu_streamoptions_default_ex_trim_whitespace();
|
|
||||||
}
|
|
||||||
|
|
||||||
config_stream->trim_class_attr = trim_class_attr;
|
|
||||||
config_stream->decode_entities = decode_entities;
|
|
||||||
config_stream->min_conditional_comments = min_conditional_comments;
|
|
||||||
config_stream->remove_attr_quotes = remove_attr_quotes;
|
|
||||||
config_stream->remove_comments = remove_comments;
|
|
||||||
config_stream->remove_optional_tags = remove_optional_tags;
|
|
||||||
config_stream->remove_tag_whitespace = remove_tag_whitespace;
|
|
||||||
|
|
||||||
pipe = hbu_pipe_create_blank(input_path);
|
|
||||||
|
|
||||||
if (input_code != NULL) {
|
|
||||||
// Use provided code as input
|
|
||||||
input_buffer = hbu_list_char_create();
|
|
||||||
hbu_list_char_extend_arr(input_buffer, (hb_char_t *) input_code, input_code_length);
|
|
||||||
hbu_pipe_blank_set_input_buffer(pipe, input_buffer);
|
|
||||||
} else {
|
|
||||||
// Read from a file as input
|
|
||||||
input_file = HBE_CATCH_F(hbu_fstreamin_create, input_path);
|
|
||||||
hbu_pipe_blank_set_input_fstreamin(pipe, input_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config_buffer || input_code != NULL) {
|
|
||||||
// Direct output to a buffer if --buffer or input is code (not file)
|
|
||||||
output_buffer = hbu_list_char_create();
|
|
||||||
hbu_pipe_blank_set_output_buffer(pipe, output_buffer);
|
|
||||||
} else {
|
|
||||||
// Direct output to a file
|
|
||||||
output_file = HBE_CATCH_F(hbu_fstreamout_create, output_path);
|
|
||||||
hbu_pipe_blank_set_output_fstreamout(pipe, output_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Magic
|
|
||||||
HBE_CATCH_F(hbs_content, config_stream, pipe, NULL);
|
|
||||||
|
|
||||||
if (output_code != NULL) {
|
|
||||||
// Send back pointer to underlying data in output buffer
|
|
||||||
*output_code = (char *) hbu_list_char_underlying(output_buffer);
|
|
||||||
*output_code_length = output_buffer->length;
|
|
||||||
hbu_list_char_destroy_shallow(output_buffer);
|
|
||||||
output_buffer = NULL;
|
|
||||||
} else if (config_buffer) {
|
|
||||||
// Write buffered output data to file
|
|
||||||
output_file = HBE_CATCH_F(hbu_fstreamout_create, output_path);
|
|
||||||
HBE_CATCH_F(hbu_fstreamout_write_buffer, output_file, output_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
finally:
|
|
||||||
if (err != NULL) {
|
|
||||||
if (output_file != NULL && input_buffer == NULL && !config_keep) {
|
|
||||||
// Delete only after opening output stream (don't delete before existing file has not been touched)
|
|
||||||
// Don't need to set if $config_buffer, as it won't write anything anyway
|
|
||||||
if (unlink(output_path)) {
|
|
||||||
hbl_log(HBL_LOG_WARN, "Failed to delete file %s with error %d", output_path, errno);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't overwrite any existing err
|
|
||||||
if (input_file != NULL) {
|
|
||||||
hbe_err_t fstreamin_destroy_error = NULL;
|
|
||||||
hbu_fstreamin_destroy(&fstreamin_destroy_error, input_file);
|
|
||||||
if (fstreamin_destroy_error != NULL) {
|
|
||||||
hbl_error(fstreamin_destroy_error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input_buffer != NULL) {
|
|
||||||
hbu_list_char_destroy(input_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't overwrite any existing err
|
|
||||||
if (output_file != NULL) {
|
|
||||||
hbe_err_t fstreamout_destroy_error = NULL;
|
|
||||||
hbu_fstreamout_destroy(&fstreamout_destroy_error, output_file);
|
|
||||||
if (fstreamout_destroy_error != NULL) {
|
|
||||||
hbl_error(fstreamout_destroy_error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (output_buffer != NULL) {
|
|
||||||
hbu_list_char_destroy(output_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
hbu_streamoptions_destroy(config_stream);
|
|
||||||
|
|
||||||
if (pipe != NULL) {
|
|
||||||
hbu_pipe_destroy(pipe);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ex_collapse_whitespace_set != NULL) {
|
|
||||||
nh_set_str_destroy(ex_collapse_whitespace_set);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ex_destroy_whole_whitespace_set != NULL) {
|
|
||||||
nh_set_str_destroy(ex_destroy_whole_whitespace_set);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ex_trim_whitespace_set != NULL) {
|
|
||||||
nh_set_str_destroy(ex_trim_whitespace_set);
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
(function() {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
let lines = [];
|
|
||||||
document.querySelectorAll(".named").forEach(t => {
|
|
||||||
let hex = t.nextElementSibling.textContent.slice(3, -1);
|
|
||||||
t.textContent.trim().split(/\s+/).map(raw => {
|
|
||||||
let r = raw.slice(1, -1);
|
|
||||||
lines.push([r, Number.parseInt(hex, 16)]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(lines.map(l => {
|
|
||||||
return `nh_map_str_int32_set(hbr_entityrefs_map, "${l[0]}", 0x${l[1].toString(16)});`
|
|
||||||
}).sort().join("\n"));
|
|
||||||
})();
|
|
|
@ -1,233 +0,0 @@
|
||||||
declare var _em_init: any;
|
|
||||||
declare var _free: any;
|
|
||||||
declare var _hbe_err_code: any;
|
|
||||||
declare var _hbe_err_destroy: any;
|
|
||||||
declare var _hbe_err_message: any;
|
|
||||||
declare var _malloc: any;
|
|
||||||
declare var ALLOC_NORMAL: any;
|
|
||||||
declare var allocate: any;
|
|
||||||
declare var cwrap: any;
|
|
||||||
declare var getValue: any;
|
|
||||||
declare var lengthBytesUTF8: any;
|
|
||||||
declare var Pointer_stringify: any;
|
|
||||||
declare var stringToUTF8: any;
|
|
||||||
declare var UTF8ToString: any;
|
|
||||||
|
|
||||||
export interface IHyperbuildSettings<O extends string | undefined> {
|
|
||||||
keep?: boolean;
|
|
||||||
buffer?: boolean;
|
|
||||||
|
|
||||||
inputCode?: string;
|
|
||||||
inputFile?: string;
|
|
||||||
outputFile?: O;
|
|
||||||
|
|
||||||
suppress?: string[];
|
|
||||||
|
|
||||||
MXcollapseWhitespace?: string[];
|
|
||||||
MXdestroyWholeWhitespace?: string[];
|
|
||||||
MXtrimWhitespace?: string[];
|
|
||||||
|
|
||||||
trim_class_attr?: boolean;
|
|
||||||
decode_entities?: boolean;
|
|
||||||
min_conditional_comments?: boolean;
|
|
||||||
remove_attr_quotes?: boolean;
|
|
||||||
remove_comments?: boolean;
|
|
||||||
remove_optional_tags?: boolean;
|
|
||||||
remove_tag_whitespace?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class HyperbuildError extends Error {
|
|
||||||
code: number;
|
|
||||||
|
|
||||||
public constructor(code: number, message: string) {
|
|
||||||
super();
|
|
||||||
this.code = code;
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const hyperbuild_c_arg_types = [
|
|
||||||
'pointer', // input_code
|
|
||||||
'number', // input_code_length
|
|
||||||
|
|
||||||
'string', // input_path
|
|
||||||
|
|
||||||
'number', // output_code (pointer)
|
|
||||||
'number', // output_code_length (pointer)
|
|
||||||
|
|
||||||
'string', // output_path
|
|
||||||
|
|
||||||
'boolean', // config_keep
|
|
||||||
'boolean', // config_buffer
|
|
||||||
|
|
||||||
'string', // suppress
|
|
||||||
|
|
||||||
'boolean', // nondefault_ex_collapse_whitespace
|
|
||||||
'string', // ex_collapse_whitespace
|
|
||||||
'boolean', // nondefault_ex_destroy_whole_whitespace
|
|
||||||
'string', // ex_destroy_whole_whitespace
|
|
||||||
'boolean', // nondefault_ex_trim_whitespace
|
|
||||||
'string', // ex_trim_whitespace
|
|
||||||
|
|
||||||
'boolean', // trim_class_attr
|
|
||||||
'boolean', // decode_entities
|
|
||||||
'boolean', // min_conditional_comments
|
|
||||||
'boolean', // remove_attr_quotes
|
|
||||||
'boolean', // remove_comments
|
|
||||||
'boolean', // remove_optional_tags
|
|
||||||
'boolean', // remove_tag_whitespace
|
|
||||||
];
|
|
||||||
|
|
||||||
const hyperbuild_c = cwrap('em_entry', 'number', hyperbuild_c_arg_types);
|
|
||||||
|
|
||||||
export interface IHyperbuild {
|
|
||||||
<O extends string | undefined>(settings: IHyperbuildSettings<O>): O
|
|
||||||
}
|
|
||||||
|
|
||||||
export function hyperbuild<O extends string | undefined>({
|
|
||||||
keep = false,
|
|
||||||
buffer = false,
|
|
||||||
|
|
||||||
inputCode,
|
|
||||||
inputFile,
|
|
||||||
outputFile,
|
|
||||||
|
|
||||||
suppress,
|
|
||||||
|
|
||||||
MXcollapseWhitespace,
|
|
||||||
MXdestroyWholeWhitespace,
|
|
||||||
MXtrimWhitespace,
|
|
||||||
|
|
||||||
trim_class_attr = true,
|
|
||||||
decode_entities = true,
|
|
||||||
min_conditional_comments = true,
|
|
||||||
remove_attr_quotes = true,
|
|
||||||
remove_comments = true,
|
|
||||||
remove_optional_tags = true,
|
|
||||||
remove_tag_whitespace = true,
|
|
||||||
}: IHyperbuildSettings<O>): O {
|
|
||||||
let args: any[] = hyperbuild_c_arg_types.map(() => null);
|
|
||||||
|
|
||||||
let input_code_ptr = 0;
|
|
||||||
|
|
||||||
let output_ptr = 0;
|
|
||||||
let output_size_ptr = 0;
|
|
||||||
|
|
||||||
if (inputCode != undefined) {
|
|
||||||
let bytes = lengthBytesUTF8(inputCode);
|
|
||||||
args[0] = input_code_ptr = _malloc(bytes + 1);
|
|
||||||
stringToUTF8(inputCode, input_code_ptr, bytes + 1);
|
|
||||||
args[1] = bytes;
|
|
||||||
} else {
|
|
||||||
args[2] = inputFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outputFile == undefined) {
|
|
||||||
// Pointers are 32-bit integers in Emscripten
|
|
||||||
// https://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.htm
|
|
||||||
args[3] = output_ptr = allocate([0], "*", ALLOC_NORMAL);
|
|
||||||
args[4] = output_size_ptr = allocate([0], "*", ALLOC_NORMAL);
|
|
||||||
} else {
|
|
||||||
args[5] = outputFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
args[6] = keep;
|
|
||||||
args[7] = buffer;
|
|
||||||
|
|
||||||
if (suppress != undefined) {
|
|
||||||
args[8] = suppress.join(",");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MXcollapseWhitespace != undefined) {
|
|
||||||
args[9] = true;
|
|
||||||
args[10] = MXcollapseWhitespace.join(",");
|
|
||||||
} else {
|
|
||||||
args[9] = false;
|
|
||||||
}
|
|
||||||
if (MXdestroyWholeWhitespace != undefined) {
|
|
||||||
args[11] = true;
|
|
||||||
args[12] = MXdestroyWholeWhitespace.join(",");
|
|
||||||
} else {
|
|
||||||
args[11] = false;
|
|
||||||
}
|
|
||||||
if (MXtrimWhitespace != undefined) {
|
|
||||||
args[13] = true;
|
|
||||||
args[14] = MXtrimWhitespace.join(",");
|
|
||||||
} else {
|
|
||||||
args[13] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
args[15] = trim_class_attr;
|
|
||||||
args[16] = decode_entities;
|
|
||||||
args[17] = min_conditional_comments;
|
|
||||||
args[18] = remove_attr_quotes;
|
|
||||||
args[19] = remove_comments;
|
|
||||||
args[20] = remove_optional_tags;
|
|
||||||
args[21] = remove_tag_whitespace;
|
|
||||||
|
|
||||||
let err = null;
|
|
||||||
|
|
||||||
let err_ptr = hyperbuild_c.apply(undefined, args);
|
|
||||||
if (err_ptr) {
|
|
||||||
let err_code = _hbe_err_code(err_ptr);
|
|
||||||
// TODO Does this work with non-ASCII?
|
|
||||||
// TODO Needs length as error message might contain NUL
|
|
||||||
let err_message = Pointer_stringify(_hbe_err_message(err_ptr));
|
|
||||||
_hbe_err_destroy(err_ptr);
|
|
||||||
err = new HyperbuildError(err_code, err_message);
|
|
||||||
}
|
|
||||||
|
|
||||||
let rv: O = undefined as O;
|
|
||||||
|
|
||||||
if (output_ptr) {
|
|
||||||
// TODO Figure out size_t
|
|
||||||
let length = getValue(output_size_ptr, "i64");
|
|
||||||
// TODO Does this work with non-ASCII?
|
|
||||||
rv = Pointer_stringify(getValue(output_ptr, "*"), length) as O;
|
|
||||||
}
|
|
||||||
|
|
||||||
[input_code_ptr, output_ptr, output_size_ptr].forEach(ptr => {
|
|
||||||
if (ptr) {
|
|
||||||
_free(ptr);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
let loaded = false;
|
|
||||||
const onload_functions: ((hyperbuild: IHyperbuild) => any)[] = [];
|
|
||||||
const onload_promises: Function[] = [];
|
|
||||||
|
|
||||||
export function onload(callback: (hyperbuild: IHyperbuild) => any) {
|
|
||||||
if (loaded) {
|
|
||||||
callback(hyperbuild);
|
|
||||||
} else {
|
|
||||||
onload_functions.push(callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function load(): Promise<IHyperbuild> {
|
|
||||||
if (loaded) {
|
|
||||||
return Promise.resolve(hyperbuild);
|
|
||||||
} else {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
onload_promises.push(resolve);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Module['onRuntimeInitialized'] = () => {
|
|
||||||
_em_init();
|
|
||||||
loaded = true;
|
|
||||||
onload_functions.forEach(fn => {
|
|
||||||
fn(hyperbuild);
|
|
||||||
});
|
|
||||||
onload_promises.forEach(res => {
|
|
||||||
res(hyperbuild);
|
|
||||||
});
|
|
||||||
};
|
|
|
@ -1,70 +0,0 @@
|
||||||
import {expect} from "chai";
|
|
||||||
import "mocha";
|
|
||||||
|
|
||||||
const {load: loadHyperbuild, hyperbuild} = require("../../hyperbuild.em.js");
|
|
||||||
|
|
||||||
before(() => {
|
|
||||||
return loadHyperbuild();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("hyperbuild", () => {
|
|
||||||
it("should trim whitespace", () => {
|
|
||||||
expect(hyperbuild({
|
|
||||||
inputCode: `<h1> a </h1>`,
|
|
||||||
})).to.equal("<h1>a</h1>");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should destroy whole whitespace", () => {
|
|
||||||
expect(hyperbuild({
|
|
||||||
inputCode: `<div>
|
|
||||||
<section></section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<h1> Helloo </h1>
|
|
||||||
</section>
|
|
||||||
</div>`,
|
|
||||||
})).to.equal("<div><section></section><section><h1>Helloo</h1></section></div>");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should destroy whole whitespace at root", () => {
|
|
||||||
expect(hyperbuild({
|
|
||||||
inputCode: `
|
|
||||||
<div>
|
|
||||||
<section></section>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
</div>
|
|
||||||
`,
|
|
||||||
})).to.equal("<div><section></section></div><div></div>");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error on malformed entities", () => {
|
|
||||||
[
|
|
||||||
`<div>&x10FFF;</div>`,
|
|
||||||
`<div>Johnson & Johnson</div>`,
|
|
||||||
`<div>&10FFFF;</div>`,
|
|
||||||
`<div>&mdash</div>`,
|
|
||||||
].map(p => {
|
|
||||||
let err = null;
|
|
||||||
try {
|
|
||||||
hyperbuild({inputCode: p});
|
|
||||||
} catch (e) {
|
|
||||||
err = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(err)
|
|
||||||
.and.have.property("code", 65);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should decode valid entities", () => {
|
|
||||||
expect(hyperbuild({
|
|
||||||
inputCode: `<div></div>`,
|
|
||||||
})).to.equal(`<div>\u{10FFFF}</div>`);
|
|
||||||
|
|
||||||
expect(hyperbuild({
|
|
||||||
inputCode: `<div>'</div>`,
|
|
||||||
})).to.equal(`<div>'</div>`);
|
|
||||||
});
|
|
|
@ -1,32 +0,0 @@
|
||||||
{
|
|
||||||
"include": [
|
|
||||||
"src/**/*.ts"
|
|
||||||
],
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "es5",
|
|
||||||
"lib": [
|
|
||||||
"es5",
|
|
||||||
"es6",
|
|
||||||
"es7",
|
|
||||||
"es2017"
|
|
||||||
],
|
|
||||||
"module": "commonjs",
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"allowJs": false,
|
|
||||||
"declaration": true,
|
|
||||||
"outDir": "out",
|
|
||||||
"strict": true,
|
|
||||||
"suppressImplicitAnyIndexErrors": true,
|
|
||||||
"noImplicitAny": true,
|
|
||||||
"strictNullChecks": true,
|
|
||||||
"strictFunctionTypes": true,
|
|
||||||
"strictPropertyInitialization": true,
|
|
||||||
"noImplicitThis": true,
|
|
||||||
"alwaysStrict": true,
|
|
||||||
"noUnusedParameters": true,
|
|
||||||
"noImplicitReturns": true,
|
|
||||||
"noFallthroughCasesInSwitch": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue