@thiagodiogo/psjava 0.0.1-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 thiagodiogo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # psjava
2
+
3
+ Roda arquivos `.psjava` como script — Java puro, em cima do [JShell](https://docs.oracle.com/javase/9/jshell/). Sem transformação de sintaxe: o que está no arquivo é o que o `jshell` executa.
4
+
5
+ ```bash
6
+ psjava exemplo.psjava # executa o arquivo
7
+ psjava exemplo.psjava --debug # idem, e loga o tempo da execução ao final
8
+ psjava doctor # verifica se o jshell está disponível
9
+ ```
10
+
11
+ ```java
12
+ var nome = "mundo";
13
+ print("olá, " + nome);
14
+ ```
15
+
16
+ ## Helper `print`
17
+
18
+ O psjava define um `print(...)` na sessão antes do teu código (Java puro, teu
19
+ arquivo continua intocado). Tem overload para `String`, `int[]` e `List`:
20
+
21
+ ```java
22
+ print("texto"); // texto
23
+ print(new int[]{1, 2, 3}); // [1, 2, 3]
24
+ print(java.util.List.of("a", "b")); // [a, b]
25
+ ```
26
+
27
+ `System.out.println(...)` continua funcionando normalmente.
28
+
29
+ ## Requisitos
30
+
31
+ Um JDK 11+ com `jshell` no PATH. Confirme com `psjava doctor`.
32
+
33
+ ## Dev
34
+
35
+ ```bash
36
+ npm install
37
+ npm test # unit + e2e
38
+ npm run test:unit # só lógica pura (sem JDK)
39
+ npm run test:e2e # builda e roda no jshell (precisa de JDK; pula sozinho sem ele)
40
+ ```
41
+
42
+ A única coisa que o `psjava` mexe no arquivo é remover o BOM do Windows, que o
43
+ `jshell` não engole. Fora isso, é Java puro entrando no JShell.
package/bin/psjava.js ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { runCli } from '../dist/cli.js';
3
+ runCli();
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function buildProgram(): Command;
3
+ export declare function runCli(argv?: string[]): Promise<void>;
package/dist/cli.js ADDED
@@ -0,0 +1,26 @@
1
+ import { Command } from 'commander';
2
+ import { runFile } from './commands/run.js';
3
+ import { runDoctor } from './commands/doctor.js';
4
+ export function buildProgram() {
5
+ const program = new Command();
6
+ program.name('psjava').description('Roda arquivos .psjava').version('0.1.0');
7
+ program
8
+ .argument('[file]', 'arquivo .psjava')
9
+ .option('-d, --debug', 'imprime o tempo da execução ao final')
10
+ .action(async (file, opts) => {
11
+ if (!file)
12
+ return program.help();
13
+ await runFile(file, opts.debug);
14
+ });
15
+ program.command('doctor').description('Verifica o JDK (jshell)').action(runDoctor);
16
+ return program;
17
+ }
18
+ export async function runCli(argv = process.argv) {
19
+ try {
20
+ await buildProgram().parseAsync(argv);
21
+ }
22
+ catch (err) {
23
+ console.error(`\nErro: ${err instanceof Error ? err.message : String(err)}`);
24
+ process.exitCode = 1;
25
+ }
26
+ }
@@ -0,0 +1 @@
1
+ export declare function runDoctor(): Promise<void>;
@@ -0,0 +1,12 @@
1
+ import chalk from 'chalk';
2
+ import { resolveJshell } from '../core/jdk.js';
3
+ export async function runDoctor() {
4
+ try {
5
+ await resolveJshell();
6
+ console.log(chalk.green('✓ jshell encontrado — pronto pra rodar .psjava'));
7
+ }
8
+ catch (err) {
9
+ console.log(chalk.red(`✗ ${err instanceof Error ? err.message : String(err)}`));
10
+ process.exitCode = 1;
11
+ }
12
+ }
@@ -0,0 +1,3 @@
1
+ /** Nomes a tentar. Só roda .psjava; sem extensão, assume .psjava. Outra extensão é recusada. */
2
+ export declare function scriptCandidates(file: string): string[];
3
+ export declare function runFile(file: string, debug?: boolean): Promise<void>;
@@ -0,0 +1,26 @@
1
+ import { readFile } from 'fs/promises';
2
+ import { existsSync } from 'fs';
3
+ import { runSource } from '../core/runner.js';
4
+ /** Nomes a tentar. Só roda .psjava; sem extensão, assume .psjava. Outra extensão é recusada. */
5
+ export function scriptCandidates(file) {
6
+ if (file.endsWith('.psjava'))
7
+ return [file];
8
+ const base = file.split(/[/\\]/).pop() ?? file;
9
+ if (base.includes('.'))
10
+ return []; // tem outra extensão (.java etc) → psjava não roda
11
+ return [`${file}.psjava`]; // sem extensão → .psjava implícito
12
+ }
13
+ export async function runFile(file, debug = false) {
14
+ const tried = scriptCandidates(file);
15
+ if (tried.length === 0) {
16
+ throw new Error(`psjava só roda arquivos .psjava (recebi: ${file})`);
17
+ }
18
+ const found = tried.find((f) => existsSync(f));
19
+ if (!found) {
20
+ throw new Error(`não encontrei o arquivo. Tentei: ${tried.join(', ')}`);
21
+ }
22
+ const source = await readFile(found, 'utf8');
23
+ const code = await runSource(source, debug);
24
+ if (code !== 0)
25
+ process.exitCode = code;
26
+ }
@@ -0,0 +1,2 @@
1
+ /** Acha o jshell no PATH e confirma que roda. Lança erro amigável se faltar. */
2
+ export declare function resolveJshell(): Promise<string>;
@@ -0,0 +1,13 @@
1
+ import { execFile } from 'child_process';
2
+ import { promisify } from 'util';
3
+ const exec = promisify(execFile);
4
+ /** Acha o jshell no PATH e confirma que roda. Lança erro amigável se faltar. */
5
+ export async function resolveJshell() {
6
+ try {
7
+ await exec('jshell', ['--version']);
8
+ return 'jshell';
9
+ }
10
+ catch {
11
+ throw new Error('jshell não encontrado. Instale um JDK (11+) e garanta que o jshell está no PATH.');
12
+ }
13
+ }
@@ -0,0 +1,3 @@
1
+ /** Monta o que vai pro jshell: preâmbulo + código do usuário (só tira o BOM do Windows). */
2
+ export declare function buildSession(source: string): string;
3
+ export declare function runSource(source: string, debug?: boolean): Promise<number>;
@@ -0,0 +1,30 @@
1
+ import { spawn } from 'child_process';
2
+ import chalk from 'chalk';
3
+ import { resolveJshell } from './jdk.js';
4
+ // Helpers definidos na sessão antes do código do usuário — Java puro, ele só chama print(...).
5
+ const PRELUDE = [
6
+ 'void print(String s) { System.out.println(s); }',
7
+ 'void print(int[] a) { System.out.println(java.util.Arrays.toString(a)); }',
8
+ 'void print(java.util.List<?> l) { System.out.println(l); }',
9
+ ].join('\n');
10
+ /** Monta o que vai pro jshell: preâmbulo + código do usuário (só tira o BOM do Windows). */
11
+ export function buildSession(source) {
12
+ return `${PRELUDE}\n${source.replace(/^/, '')}`; // ponytail: BOM é lixo de encoding, não é edição do código
13
+ }
14
+ export async function runSource(source, debug = false) {
15
+ const jshell = await resolveJshell(); // erro amigável se faltar JDK
16
+ const code = buildSession(source);
17
+ const start = performance.now();
18
+ return new Promise((resolve) => {
19
+ // -s: modo script silencioso (sem banner/prompt); lê de stdin e sai sozinho
20
+ const p = spawn(jshell, ['-s', '-'], { stdio: ['pipe', 'inherit', 'inherit'] });
21
+ p.stdin.end(code + '\n');
22
+ p.on('close', (c) => {
23
+ if (debug) {
24
+ const s = ((performance.now() - start) / 1000).toFixed(2);
25
+ console.error(chalk.dim(`[psjava] concluído em ${s}s`));
26
+ }
27
+ resolve(c ?? 0);
28
+ });
29
+ });
30
+ }
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@thiagodiogo/psjava",
3
+ "version": "0.0.1-beta.0",
4
+ "description": "Roda arquivos .psjava como script — Java sem cerimônia, em cima do JShell.",
5
+ "keywords": [
6
+ "psjava",
7
+ "java",
8
+ "jshell",
9
+ "cli",
10
+ "script"
11
+ ],
12
+ "homepage": "https://github.com/eipastel/psjava",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/eipastel/psjava.git"
16
+ },
17
+ "bugs": {
18
+ "url": "https://github.com/eipastel/psjava/issues"
19
+ },
20
+ "license": "MIT",
21
+ "author": "thiagodiogo",
22
+ "type": "module",
23
+ "bin": {
24
+ "psjava": "bin/psjava.js"
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "bin"
29
+ ],
30
+ "engines": {
31
+ "node": ">=20"
32
+ },
33
+ "publishConfig": {
34
+ "access": "public"
35
+ },
36
+ "scripts": {
37
+ "prebuild": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
38
+ "build": "tsc",
39
+ "dev": "tsc --watch",
40
+ "test": "npm run test:unit && npm run test:e2e",
41
+ "test:unit": "vitest run",
42
+ "test:e2e": "npm run build && vitest run --config vitest.e2e.config.ts",
43
+ "prepublishOnly": "npm run build"
44
+ },
45
+ "dependencies": {
46
+ "chalk": "^5.5.0",
47
+ "commander": "^14.0.0"
48
+ },
49
+ "devDependencies": {
50
+ "@types/node": "^24",
51
+ "typescript": "^5.9",
52
+ "vitest": "^3"
53
+ }
54
+ }