Skip to content
26 changes: 26 additions & 0 deletions tests/commonjs_caching_001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--TEST--
Test V8Js::setModuleLoader : Returned modules are cached
--SKIPIF--
<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
--FILE--
<?php

$JS = <<< EOT
var foo = require("test");
var bar = require("test2");
var baz = require("test");
EOT;

$v8 = new V8Js();
$v8->setModuleLoader(function($module) {
print("setModuleLoader called for ".$module."\n");
return 'exports.bar = 23;';
});

$v8->executeString($JS, 'module.js');
?>
===EOF===
--EXPECT--
setModuleLoader called for test
setModuleLoader called for test2
===EOF===
34 changes: 34 additions & 0 deletions tests/commonjs_caching_002.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
--TEST--
Test V8Js::setModuleLoader : module cache seperated per isolate
--SKIPIF--
<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
--FILE--
<?php

$JS = <<< EOT
var foo = require("test");
var baz = require("test");
EOT;

$v8 = new V8Js();
$v8->setModuleLoader(function($module) {
print("setModuleLoader called for ".$module."\n");
return 'exports.bar = 23;';
});

$v8two = new V8Js();
$v8two->setModuleLoader(function($module) {
print("setModuleLoader called for ".$module."\n");
return 'exports.bar = 23;';
});

$v8->executeString($JS, 'module.js');
echo "--- v8two ---\n";
$v8two->executeString($JS, 'module.js');
?>
===EOF===
--EXPECT--
setModuleLoader called for test
--- v8two ---
setModuleLoader called for test
===EOF===
23 changes: 23 additions & 0 deletions tests/commonjs_normalise_001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
--TEST--
Test V8Js::setModuleLoader : Path normalisation #001
--SKIPIF--
<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
--FILE--
<?php

$JS = <<< EOT
var foo = require("./test");
EOT;

$v8 = new V8Js();
$v8->setModuleLoader(function($module) {
print("setModuleLoader called for ".$module."\n");
return 'exports.bar = 23;';
});

$v8->executeString($JS, 'module.js');
?>
===EOF===
--EXPECT--
setModuleLoader called for test
===EOF===
23 changes: 23 additions & 0 deletions tests/commonjs_normalise_002.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
--TEST--
Test V8Js::setModuleLoader : Path normalisation #002
--SKIPIF--
<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
--FILE--
<?php

$JS = <<< EOT
var foo = require("../../../test");
EOT;

$v8 = new V8Js();
$v8->setModuleLoader(function($module) {
print("setModuleLoader called for ".$module."\n");
return 'exports.bar = 23;';
});

$v8->executeString($JS, 'module.js');
?>
===EOF===
--EXPECT--
setModuleLoader called for test
===EOF===
27 changes: 27 additions & 0 deletions tests/commonjs_normalise_003.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--TEST--
Test V8Js::setModuleLoader : Path normalisation #003
--SKIPIF--
<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
--FILE--
<?php

$JS = <<< EOT
var foo = require("foo/test");
var foo = require("foo/bar/baz/test");
var foo = require("foo//bar//baz//blub");
EOT;

$v8 = new V8Js();
$v8->setModuleLoader(function($module) {
print("setModuleLoader called for ".$module."\n");
return 'exports.bar = 23;';
});

$v8->executeString($JS, 'module.js');
?>
===EOF===
--EXPECT--
setModuleLoader called for foo/test
setModuleLoader called for foo/bar/baz/test
setModuleLoader called for foo/bar/baz/blub
===EOF===
30 changes: 30 additions & 0 deletions tests/commonjs_normalise_004.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
--TEST--
Test V8Js::setModuleLoader : Path normalisation #004
--SKIPIF--
<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
--FILE--
<?php

$JS = <<< EOT
var foo = require("foo/test");
EOT;

$v8 = new V8Js();
$v8->setModuleLoader(function($module) {
print("setModuleLoader called for ".$module."\n");

switch($module) {
case 'foo/test':
return 'require("./blar");';
case 'foo/blar':
return 'exports.bar = 23;';
}
});

$v8->executeString($JS, 'module.js');
?>
===EOF===
--EXPECT--
setModuleLoader called for foo/test
setModuleLoader called for foo/blar
===EOF===
30 changes: 30 additions & 0 deletions tests/commonjs_normalise_005.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
--TEST--
Test V8Js::setModuleLoader : Path normalisation #005
--SKIPIF--
<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
--FILE--
<?php

$JS = <<< EOT
var foo = require("foo/test");
EOT;

$v8 = new V8Js();
$v8->setModuleLoader(function($module) {
print("setModuleLoader called for ".$module."\n");

switch($module) {
case 'foo/test':
return 'require("../blar");';
case 'blar':
return 'exports.bar = 23;';
}
});

$v8->executeString($JS, 'module.js');
?>
===EOF===
--EXPECT--
setModuleLoader called for foo/test
setModuleLoader called for blar
===EOF===
3 changes: 2 additions & 1 deletion v8js_class.cc
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ static void v8js_free_storage(void *object TSRMLS_DC) /* {{{ */
/* Clear persistent handles in module cache */
for (std::map<char *, v8js_persistent_obj_t>::iterator it = c->modules_loaded.begin();
it != c->modules_loaded.end(); ++it) {
efree(it->first);
it->second.Reset();
}
c->modules_loaded.~map();
Expand Down Expand Up @@ -200,7 +201,7 @@ static zend_object_value v8js_new(zend_class_entry *ce TSRMLS_DC) /* {{{ */

new(&c->modules_stack) std::vector<char*>();
new(&c->modules_base) std::vector<char*>();
new(&c->modules_loaded) std::map<char *, v8js_persistent_obj_t>;
new(&c->modules_loaded) std::map<char *, v8js_persistent_obj_t, cmp_str>;

new(&c->template_cache) std::map<const char *,v8js_tmpl_t>();
new(&c->accessor_list) std::vector<v8js_accessor_ctx *>();
Expand Down
8 changes: 7 additions & 1 deletion v8js_class.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> > v8
struct v8js_v8object;
struct v8js_accessor_ctx;

struct cmp_str {
bool operator()(char const *a, char const *b) const {
return strcmp(a, b) < 0;
}
};

/* {{{ Context container */
struct v8js_ctx {
zend_object std;
Expand All @@ -43,7 +49,7 @@ struct v8js_ctx {
zval *module_loader;
std::vector<char *> modules_stack;
std::vector<char *> modules_base;
std::map<char *, v8js_persistent_obj_t> modules_loaded;
std::map<char *, v8js_persistent_obj_t, cmp_str> modules_loaded;
std::map<const char *,v8js_tmpl_t> template_cache;

std::map<zval *, v8js_persistent_obj_t> weak_objects;
Expand Down
34 changes: 19 additions & 15 deletions v8js_commonjs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,18 @@ extern "C" {

#include "php_v8js_macros.h"

void v8js_commonjs_split_terms(char *identifier, std::vector<char *> &terms)
static void v8js_commonjs_split_terms(const char *identifier, std::vector<char *> &terms)
{
char *term = (char *)malloc(PATH_MAX), *ptr = term;

// Initialise the term string
*term = 0;
char *term = (char *) emalloc(PATH_MAX), *ptr = term;

while (*identifier > 0) {
if (*identifier == '/') {
if (strlen(term) > 0) {
if (ptr > term) {
// Terminate term string and add to terms vector
*ptr++ = 0;
terms.push_back(strdup(term));
terms.push_back(estrdup(term));

// Reset term string
memset(term, 0, strlen(term));
ptr = term;
}
} else {
Expand All @@ -47,18 +43,16 @@ void v8js_commonjs_split_terms(char *identifier, std::vector<char *> &terms)
identifier++;
}

if (strlen(term) > 0) {
if (ptr > term) {
// Terminate term string and add to terms vector
*ptr++ = 0;
terms.push_back(strdup(term));
terms.push_back(estrdup(term));
}

if (term > 0) {
free(term);
}
efree(term);
}

void v8js_commonjs_normalise_identifier(char *base, char *identifier, char *normalised_path, char *module_name)
void v8js_commonjs_normalise_identifier(const char *base, const char *identifier, char *normalised_path, char *module_name)
{
std::vector<char *> id_terms, terms;
v8js_commonjs_split_terms(identifier, id_terms);
Expand All @@ -78,12 +72,19 @@ void v8js_commonjs_normalise_identifier(char *base, char *identifier, char *norm
if (!strcmp(term, "..")) {
// Ignore parent term (..) if it's the first normalised term
if (normalised_terms.size() > 0) {
// Remove the parent normalized term
// Remove the parent normalized term (and free it)
efree(normalised_terms.back());
normalised_terms.pop_back();
}

// free the ".." term
efree(term);
} else if (strcmp(term, ".")) {
// Add the term if it's not the current term (.)
normalised_terms.push_back(term);
} else {
// Discard "." term
efree(term);
}
}

Expand All @@ -92,6 +93,8 @@ void v8js_commonjs_normalise_identifier(char *base, char *identifier, char *norm
*module_name = 0;

strcat(module_name, normalised_terms.back());

efree(normalised_terms.back());
normalised_terms.pop_back();

for (std::vector<char *>::iterator it = normalised_terms.begin(); it != normalised_terms.end(); it++) {
Expand All @@ -102,5 +105,6 @@ void v8js_commonjs_normalise_identifier(char *base, char *identifier, char *norm
}

strcat(normalised_path, term);
efree(term);
}
}
18 changes: 18 additions & 0 deletions v8js_commonjs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2015 The PHP Group |
+----------------------------------------------------------------------+
| http://www.opensource.org/licenses/mit-license.php MIT License |
+----------------------------------------------------------------------+
| Author: Stefan Siegl <stesie@brokenpipe.de> |
+----------------------------------------------------------------------+
*/

#ifndef V8JS_COMMONJS_H
#define V8JS_COMMONJS_H

void v8js_commonjs_normalise_identifier(const char *base, const char *identifier, char *normalised_path, char *module_name);

#endif /* V8JS_COMMONJS_H */
Loading