rip-lang 3.17.1 → 3.17.2
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/README.md +1 -1
- package/docs/dist/rip.js +18 -3
- package/docs/dist/rip.min.js +90 -90
- package/docs/dist/rip.min.js.br +0 -0
- package/package.json +1 -1
- package/scripts/serve.js +33 -24
- package/src/types.js +15 -4
package/docs/dist/rip.min.js.br
CHANGED
|
Binary file
|
package/package.json
CHANGED
package/scripts/serve.js
CHANGED
|
@@ -27,6 +27,30 @@ const MIME_TYPES = {
|
|
|
27
27
|
'.rip': 'text/plain; charset=utf-8'
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
+
// ETag (size+mtime, plus encoding so brotli/plain get distinct tags) +
|
|
31
|
+
// no-cache for cheap 304 revalidation, and Vary so caches don't mix encodings.
|
|
32
|
+
// Returns null if unreadable, letting the caller fall back.
|
|
33
|
+
function serveFile(req, diskPath, contentType, encoding) {
|
|
34
|
+
let stat;
|
|
35
|
+
try { stat = statSync(diskPath); } catch { return null; }
|
|
36
|
+
const etag = `"${stat.size.toString(16)}-${Math.round(stat.mtimeMs).toString(16)}${encoding ? '-' + encoding : ''}"`;
|
|
37
|
+
const headers = {
|
|
38
|
+
'Content-Type': contentType,
|
|
39
|
+
'ETag': etag,
|
|
40
|
+
'Cache-Control': 'no-cache',
|
|
41
|
+
'Vary': 'Accept-Encoding'
|
|
42
|
+
};
|
|
43
|
+
if (encoding) headers['Content-Encoding'] = encoding;
|
|
44
|
+
if (req.headers.get('if-none-match') === etag) {
|
|
45
|
+
return new Response(null, { status: 304, headers });
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
return new Response(readFileSync(diskPath), { headers });
|
|
49
|
+
} catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
30
54
|
// Request handler for serving files
|
|
31
55
|
function handleRequest(req) {
|
|
32
56
|
const url = new URL(req.url);
|
|
@@ -50,34 +74,19 @@ function handleRequest(req) {
|
|
|
50
74
|
const filePath = join(ROOT, pathname);
|
|
51
75
|
const ext = extname(pathname);
|
|
52
76
|
const acceptEncoding = req.headers.get('accept-encoding') || '';
|
|
77
|
+
const contentType = MIME_TYPES[ext] || 'application/octet-stream';
|
|
53
78
|
|
|
54
|
-
//
|
|
79
|
+
// Prefer the pre-compressed Brotli sidecar when the client accepts it.
|
|
55
80
|
if (acceptEncoding.includes('br') && existsSync(filePath + '.br')) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return new Response(compressed, {
|
|
59
|
-
headers: {
|
|
60
|
-
'Content-Type': MIME_TYPES[ext] || 'application/octet-stream',
|
|
61
|
-
'Content-Encoding': 'br',
|
|
62
|
-
'Cache-Control': 'no-cache'
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
} catch (e) {
|
|
66
|
-
// Fall through to regular file
|
|
67
|
-
}
|
|
81
|
+
const res = serveFile(req, filePath + '.br', contentType, 'br');
|
|
82
|
+
if (res) return res;
|
|
68
83
|
}
|
|
69
84
|
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
'Content-Type': MIME_TYPES[ext] || 'application/octet-stream'
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
} catch (e) {
|
|
79
|
-
return new Response('404 Not Found', { status: 404 });
|
|
80
|
-
}
|
|
85
|
+
// Plain file — also the failover when no .br sidecar exists.
|
|
86
|
+
const res = serveFile(req, filePath, contentType, null);
|
|
87
|
+
if (res) return res;
|
|
88
|
+
|
|
89
|
+
return new Response('404 Not Found', { status: 404 });
|
|
81
90
|
}
|
|
82
91
|
|
|
83
92
|
// Try to start server on preferred port, fallback to OS-assigned port
|
package/src/types.js
CHANGED
|
@@ -405,12 +405,23 @@ function looksLikeBareFunctionType(typeTokens) {
|
|
|
405
405
|
// left alone and any side effects survive.
|
|
406
406
|
function isCompleteTypeExpr(tokens, a, b) {
|
|
407
407
|
if (b <= a) return false;
|
|
408
|
-
const SEP = new Set(['|', '&', ',', ':', '?', '.', '...'
|
|
408
|
+
const SEP = new Set(['|', '&', ',', ':', '?', '.', '...']);
|
|
409
409
|
let par = 0, brk = 0, brc = 0, gen = 0, atomEnd = false;
|
|
410
|
+
const parInfo = []; // per-paren-depth: { colon, open }
|
|
411
|
+
let lastClosedParen = null; // { colon, empty } of the most recently closed group
|
|
410
412
|
for (let j = a; j < b; j++) {
|
|
411
413
|
const t = tokens[j][0], v = tokens[j][1];
|
|
412
|
-
|
|
413
|
-
|
|
414
|
+
// Function-type arrow: valid only after a closed param group that is empty
|
|
415
|
+
// `()` or typed `(x: T)`. An untyped `(e) =>` (or leading `=>`) is a value
|
|
416
|
+
// arrow, so context B won't misread `@input: (e) => x = y` as a typed decl.
|
|
417
|
+
if (t === '=>') {
|
|
418
|
+
const p = j > a ? tokens[j - 1][0] : null;
|
|
419
|
+
if ((p === ')' || p === 'PARAM_END') && lastClosedParen &&
|
|
420
|
+
(lastClosedParen.colon || lastClosedParen.empty)) { atomEnd = false; continue; }
|
|
421
|
+
return false;
|
|
422
|
+
}
|
|
423
|
+
if (t === '(' || t === 'PARAM_START') { parInfo.push({ colon: false, open: j }); par++; atomEnd = false; continue; }
|
|
424
|
+
if (t === ')' || t === 'PARAM_END') { if (--par < 0) return false; const pi = parInfo.pop(); lastClosedParen = pi ? { colon: pi.colon, empty: j === pi.open + 1 } : null; atomEnd = true; continue; }
|
|
414
425
|
if (t === '[' || t === 'INDEX_START') { brk++; atomEnd = false; continue; }
|
|
415
426
|
if (t === ']' || t === 'INDEX_END') { if (--brk < 0) return false; atomEnd = true; continue; }
|
|
416
427
|
if (t === '{') { brc++; atomEnd = false; continue; }
|
|
@@ -425,7 +436,7 @@ function isCompleteTypeExpr(tokens, a, b) {
|
|
|
425
436
|
return false;
|
|
426
437
|
}
|
|
427
438
|
if (t === '=') { if (gen > 0) { atomEnd = false; continue; } return false; } // generic default only
|
|
428
|
-
if (SEP.has(t)) { atomEnd = false; continue; }
|
|
439
|
+
if (SEP.has(t)) { if (t === ':' && parInfo.length) parInfo[parInfo.length - 1].colon = true; atomEnd = false; continue; }
|
|
429
440
|
if (t === 'IDENTIFIER' || t === 'PROPERTY' || t === 'NUMBER' ||
|
|
430
441
|
t === 'STRING' || t === 'NULL' || t === 'UNDEFINED' || t === 'BOOL') {
|
|
431
442
|
if (atomEnd) return false; // two atoms, no separator → not a type
|