Eshu

 view release on metacpan or  search on metacpan

t/0107-realworld-js-patterns.t  view on Meta::CPAN

this.#store.delete(key);
});

set(key, value) {
const ref = new WeakRef(value);
this.#store.set(key, ref);
this.#registry.register(value, key);
}

get(key) {
const ref = this.#store.get(key);
if (!ref) return undefined;
const val = ref.deref();
if (val === undefined) {
this.#store.delete(key);
}
return val;
}

has(key) {
return this.get(key) !== undefined;
}
}
END
    my $exp = <<'END';
class Cache {
	#store = new Map();
	#registry = new FinalizationRegistry((key) => {
		this.#store.delete(key);
	});

	set(key, value) {
		const ref = new WeakRef(value);
		this.#store.set(key, ref);
		this.#registry.register(value, key);
	}

	get(key) {
		const ref = this.#store.get(key);
		if (!ref) return undefined;
		const val = ref.deref();
		if (val === undefined) {
			this.#store.delete(key);
		}
		return val;
	}

	has(key) {
		return this.get(key) !== undefined;
	}
}
END
    is(Eshu->indent_js($in), $exp, 'JS: WeakRef cache with FinalizationRegistry callback');
}

# CommonJS module pattern
{
    my $in = <<'END';
'use strict';

const path = require('path');
const fs   = require('fs');

const DEFAULT_OPTS = {
encoding: 'utf8',
recursive: false,
filter: null,
};

function readDir(dir, opts) {
opts = Object.assign({}, DEFAULT_OPTS, opts);
const results = [];

function walk(current) {
const entries = fs.readdirSync(current, { withFileTypes: true });
for (const entry of entries) {
const full = path.join(current, entry.name);
if (entry.isDirectory()) {
if (opts.recursive) walk(full);
} else {
if (!opts.filter || opts.filter(entry.name)) {
results.push(full);
}
}
}
}

walk(dir);
return results;
}

module.exports = { readDir };
END
    my $exp = <<'END';
'use strict';

const path = require('path');
const fs   = require('fs');

const DEFAULT_OPTS = {
	encoding: 'utf8',
	recursive: false,
	filter: null,
};

function readDir(dir, opts) {
	opts = Object.assign({}, DEFAULT_OPTS, opts);
	const results = [];

	function walk(current) {
		const entries = fs.readdirSync(current, { withFileTypes: true });
		for (const entry of entries) {
			const full = path.join(current, entry.name);
			if (entry.isDirectory()) {
				if (opts.recursive) walk(full);
			} else {
				if (!opts.filter || opts.filter(entry.name)) {
					results.push(full);
				}
			}
		}
	}

	walk(dir);
	return results;
}

module.exports = { readDir };
END
    is(Eshu->indent_js($in), $exp, 'JS: CommonJS module with recursive directory walk');
}

# TypeScript-style interface comment block + type guards
{
    my $in = <<'END';
// Type guard helpers for runtime validation

function isString(val) {
return typeof val === 'string';
}

function isRecord(val) {
return val !== null && typeof val === 'object' && !Array.isArray(val);
}

function validateConfig(raw) {
if (!isRecord(raw)) throw new TypeError('config must be an object');
const { host, port, tls = false } = raw;
if (!isString(host) || host.length === 0) {
throw new TypeError('config.host must be a non-empty string');
}
if (typeof port !== 'number' || port < 1 || port > 65535) {
throw new RangeError(`config.port must be 1-65535, got ${port}`);
}
return { host, port: Math.floor(port), tls: Boolean(tls) };
}
END
    my $exp = <<'END';
// Type guard helpers for runtime validation

function isString(val) {
	return typeof val === 'string';
}

function isRecord(val) {
	return val !== null && typeof val === 'object' && !Array.isArray(val);
}

function validateConfig(raw) {
	if (!isRecord(raw)) throw new TypeError('config must be an object');
	const { host, port, tls = false } = raw;
	if (!isString(host) || host.length === 0) {
		throw new TypeError('config.host must be a non-empty string');
	}
	if (typeof port !== 'number' || port < 1 || port > 65535) {
		throw new RangeError(`config.port must be 1-65535, got ${port}`);
	}
	return { host, port: Math.floor(port), tls: Boolean(tls) };
}
END
    is(Eshu->indent_js($in), $exp, 'JS: type guard functions with destructuring and template literals');
}

# Worker thread message handler pattern
{
    my $in = <<'END';
const { parentPort, workerData } = require('worker_threads');

const handlers = {
ping(data) {
return { type: 'pong', ts: Date.now() };
},
process(data) {
const { items } = data;
const results = items.map((item) => {
try {
return { ok: true,  value: transform(item) };
} catch (err) {
return { ok: false, error: err.message };
}
});
return { type: 'result', results };
},
};

parentPort.on('message', (msg) => {
const handler = handlers[msg.type];
if (!handler) {
parentPort.postMessage({ type: 'error', message: `Unknown: ${msg.type}` });
return;
}
try {
const reply = handler(msg.data);
parentPort.postMessage(reply);
} catch (err) {
parentPort.postMessage({ type: 'error', message: err.message });
}
});
END
    my $exp = <<'END';
const { parentPort, workerData } = require('worker_threads');

const handlers = {
	ping(data) {
		return { type: 'pong', ts: Date.now() };
	},
	process(data) {
		const { items } = data;
		const results = items.map((item) => {
			try {
				return { ok: true,  value: transform(item) };
			} catch (err) {
				return { ok: false, error: err.message };
			}
		});
		return { type: 'result', results };
	},
};

parentPort.on('message', (msg) => {
	const handler = handlers[msg.type];
	if (!handler) {
		parentPort.postMessage({ type: 'error', message: `Unknown: ${msg.type}` });
		return;
	}
	try {
		const reply = handler(msg.data);
		parentPort.postMessage(reply);
	} catch (err) {
		parentPort.postMessage({ type: 'error', message: err.message });
	}
});
END
    is(Eshu->indent_js($in), $exp, 'JS: worker_threads message dispatch with try/catch');
}

# Proxy / Reflect traps
{
    my $in = <<'END';
function createReadOnlyProxy(target) {
return new Proxy(target, {
set(obj, prop, value) {
throw new TypeError(`Cannot set property "${String(prop)}" on read-only object`);
},
deleteProperty(obj, prop) {
throw new TypeError(`Cannot delete property "${String(prop)}" on read-only object`);
},
defineProperty(obj, prop, descriptor) {
throw new TypeError(`Cannot define property "${String(prop)}" on read-only object`);
},
get(obj, prop, receiver) {
const val = Reflect.get(obj, prop, receiver);
if (val !== null && typeof val === 'object') {
return createReadOnlyProxy(val);
}
return val;
},
});
}
END
    my $exp = <<'END';



( run in 1.036 second using v1.01-cache-2.11-cpan-6aa56a78535 )