Pythonic JavaScript that doesn't suck - a Python-to-JavaScript transpiler with clean syntax and performance
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Streaming compilation interface optimized for web browsers and embedded environments. Provides incremental compilation with state preservation, making it ideal for REPL-style applications and dynamic code execution.
Creates an embedded compiler instance that maintains compilation state across multiple operations.
/**
* Create an embedded compiler instance
* @param compiler - Main compiler instance from create_compiler()
* @param baselib - Base library code as string
* @param runjs - JavaScript execution function (default: eval)
* @param name - Module name for compiled code (default: '__embedded__')
* @returns Embedded compiler interface
*/
function create_embedded_compiler(
compiler: CompilerInstance,
baselib: string,
runjs?: Function,
name?: string
): EmbeddedCompiler;
interface EmbeddedCompiler {
/** Compile RapydScript code to JavaScript with state preservation */
compile(code: string, options?: EmbeddedCompileOptions): string;
/** Current top-level AST node maintaining compilation state */
toplevel: AST_Toplevel | null;
}Usage Example:
const { create_compiler } = require("rapydscript-ng");
const embedded_compiler = require("rapydscript-ng/tools/embedded_compiler");
const fs = require("fs");
// Create main compiler and load base library
const RapydScript = create_compiler();
const baselib = fs.readFileSync("path/to/baselib.js", "utf-8");
// Create embedded compiler
const embeddedCompiler = embedded_compiler(
RapydScript,
baselib,
eval,
"my_module"
);
// Compile code incrementally
const js1 = embeddedCompiler.compile(`
def greet(name):
return "Hello, " + name
`);
const js2 = embeddedCompiler.compile(`
print(greet("World"))
`);Compile RapydScript source code with incremental state management and flexible output options.
/**
* Compile RapydScript code to JavaScript
* @param code - RapydScript source code
* @param options - Compilation options
* @returns Generated JavaScript code
*/
compile(code: string, options?: EmbeddedCompileOptions): string;
interface EmbeddedCompileOptions {
/** Source filename for error reporting */
filename?: string;
/** Include base library in output */
keep_baselib?: boolean;
/** Preserve docstrings as __doc__ attributes */
keep_docstrings?: boolean;
/** Target JavaScript version (5 or 6) */
js_version?: number;
/** Wrap output in private scope */
private_scope?: boolean;
/** Include __name__ assignment */
write_name?: boolean;
/** Remove assert statements */
discard_asserts?: boolean;
}Advanced Usage:
// Configure compilation options
const options = {
filename: "repl_input.pyj",
keep_baselib: false, // Don't repeat baselib
keep_docstrings: true, // Preserve documentation
js_version: 6, // Use ES6 features
private_scope: true, // Wrap in function scope
write_name: false, // Skip __name__ assignment
discard_asserts: false // Keep assert statements
};
const javascript = embeddedCompiler.compile(`
class Calculator:
"""A simple calculator class."""
def add(self, a, b):
"""Add two numbers."""
assert isinstance(a, (int, float))
assert isinstance(b, (int, float))
return a + b
def multiply(self, a, b):
"""Multiply two numbers."""
return a * b
calc = Calculator()
result = calc.add(5, 3)
print("Result:", result)
`, options);The embedded compiler maintains compilation state across multiple compile calls, enabling:
Example - Building an Application Incrementally:
const embeddedCompiler = embedded_compiler(RapydScript, baselib);
// Step 1: Define utility functions
embeddedCompiler.compile(`
def utils_multiply(a, b):
return a * b
def utils_format(value):
return "Result: " + str(value)
`);
// Step 2: Define main class (can use previously defined functions)
embeddedCompiler.compile(`
class MathApp:
def calculate(self, x, y):
result = utils_multiply(x, y)
return utils_format(result)
`);
// Step 3: Create and use application
const finalJS = embeddedCompiler.compile(`
app = MathApp()
output = app.calculate(6, 7)
print(output) # Prints: Result: 42
`);
// All previous definitions are preserved and available
console.log(finalJS);The embedded compiler is designed for browser environments and can be integrated into web-based development tools:
HTML Integration:
<!DOCTYPE html>
<html>
<head>
<script src="rapydscript-compiler.js"></script>
<script src="rapydscript-baselib.js"></script>
</head>
<body>
<textarea id="code">
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10))
</textarea>
<button onclick="compileAndRun()">Run</button>
<pre id="output"></pre>
<script>
// Create embedded compiler
const RapydScript = window.create_compiler();
const embeddedCompiler = window.create_embedded_compiler(
RapydScript,
window.baselib_code,
function(code) {
// Custom execution function
try {
return eval(code);
} catch(e) {
document.getElementById('output').textContent = 'Error: ' + e.message;
}
}
);
function compileAndRun() {
const code = document.getElementById('code').value;
try {
const js = embeddedCompiler.compile(code);
eval(js);
} catch(e) {
document.getElementById('output').textContent = 'Compilation error: ' + e.message;
}
}
</script>
</body>
</html>The embedded compiler provides detailed error information for debugging:
try {
const result = embeddedCompiler.compile(`
def broken_function(:
return "missing parenthesis"
`);
} catch (error) {
if (error instanceof RapydScript.SyntaxError) {
console.error(`Syntax error in ${error.filename || '<embedded>'}: ${error.message}`);
if (error.line) console.error(`Line ${error.line}, Column ${error.col || 0}`);
} else {
console.error('Compilation failed:', error.message);
}
}Install with Tessl CLI
npx tessl i tessl/npm-rapydscript-ng