mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-01 07:33:12 +08:00
path.posix, path.win32 and the bare path module are one module object
each, the handle process.getBuiltinModule answers, so require('path/posix'),
path.posix and the target platform's bare path compare as Node's do, a
namespace beside other values in one slot is untyped, and path[family]
reads that object. Functions read through them take checked arguments:
each string parameter passes Node's validateString under its own name
(basename's suffix first), resolve validates paths[i] only as far as its
last-first walk reads them, parse answers an untyped { root, dir, base,
ext, name }, format follows _format over any object, and
toNamespacedPath answers a non-string as it is. A JavaScript call whose
arguments are not strings, or omit one, goes through the same checks.
Typed slots keep the typed function values.
path.win32.relative lowercases both resolved paths with
String.prototype.toLowerCase and walks them by UTF-16 unit, comparing
segments instead when lowercasing changed a length, as Node does. It
folded ASCII only, so a path with İ or Ⱥ in a different case gave a
longer relative path. The function moves into its own runtime unit,
scr_path_win32_relative.c, which links with the regex unit whose case
mapping it uses. scr_path.c stays free of it, so library and
cross-target builds that link the path functions without the regex unit
still link.
A JavaScript binding whose inferred type holds a union of functions and
arrays (a test table of [fn, cases] rows, or one destructured row) takes
the checked-dynamic kind that dynFallbackType gives the unmappable
spellings of such tables. Its rows keep their functions' names, and
for-of, forEach and destructuring read the items as untyped values.
TypeScript bindings keep their typed layout.
61 lines
2.9 KiB
JavaScript
61 lines
2.9 KiB
JavaScript
'use strict';
|
|
// node:path namespaces and functions used as values: identity, Node's
|
|
// argument validation, and the parse/format/resolve/toNamespacedPath forms.
|
|
const path = require('path');
|
|
|
|
const platform = process.platform === 'win32' ? path.win32 : path.posix;
|
|
console.log('identity',
|
|
path === platform,
|
|
require('path/posix') === path.posix,
|
|
require('path/win32') === path.win32,
|
|
path.posix.win32 === path.win32,
|
|
path.win32.posix === path.posix);
|
|
|
|
function call(fn, args) {
|
|
try {
|
|
return JSON.stringify(fn.apply(null, args));
|
|
} catch (e) {
|
|
return `${e.name} ${e.code} ${e.message}`;
|
|
}
|
|
}
|
|
|
|
for (const [name, ns] of [['posix', path.posix], ['win32', path.win32]]) {
|
|
console.log(`-- ${name}`);
|
|
for (const value of [true, 7, null, {}, undefined, []]) {
|
|
console.log('join', call(ns.join, ['a', value]));
|
|
console.log('normalize', call(ns.normalize, [value]));
|
|
console.log('basename suffix', call(ns.basename, [value, 7]));
|
|
console.log('basename', call(ns.basename, [value]));
|
|
console.log('relative from', call(ns.relative, [value, 'x']));
|
|
console.log('relative to', call(ns.relative, ['x', value]));
|
|
console.log('matchesGlob', call(ns.matchesGlob, ['a', value]));
|
|
console.log('parse', call(ns.parse, [value]));
|
|
console.log('format', call(ns.format, [value]));
|
|
console.log('toNamespacedPath', call(ns.toNamespacedPath, [value]));
|
|
}
|
|
console.log('join none', call(ns.join, []));
|
|
console.log('basename undefined suffix', call(ns.basename, ['/a/b.js', undefined]));
|
|
// resolve reads its arguments last first and stops at an absolute path.
|
|
console.log('resolve stop', call(ns.resolve, [7, '/abs/x']));
|
|
console.log('resolve bad', call(ns.resolve, ['/abs', 7, 'y']));
|
|
console.log('resolve bad last', call(ns.resolve, ['/abs', 'y', null]));
|
|
console.log('parse', call(ns.parse, ['/home/user/dir/file.txt']));
|
|
console.log('format base', call(ns.format, [{ base: 5 }]));
|
|
console.log('format dir root', call(ns.format, [{ root: '/', dir: '/', base: 'x' }]));
|
|
console.log('format ext', call(ns.format, [{ name: 'x', ext: 'png' }]),
|
|
call(ns.format, [{ name: 'x', ext: '.png' }]), call(ns.format, [{ name: 'x', ext: 5 }]));
|
|
console.log('format empty', call(ns.format, [{}]));
|
|
}
|
|
console.log('win32 resolve devices',
|
|
call(path.win32.resolve, [null, 'c:\\a', 'd:\\b']),
|
|
call(path.win32.resolve, [null, 'c:a', 'd:\\b']),
|
|
call(path.win32.resolve, [null, '\\\\server\\share\\x']),
|
|
call(path.win32.resolve, ['d:x', null, 'c:\\b']));
|
|
console.log('win32 namespaced', call(path.win32.toNamespacedPath, ['c:\\x']),
|
|
call(path.win32.toNamespacedPath, ['']));
|
|
|
|
// The same members reached through the namespace object are the same values.
|
|
const ns = path.posix;
|
|
console.log('members', ns.join === path.posix.join, typeof ns.parse, ns.sep, path.win32.delimiter);
|
|
for (const key of ['basename', 'extname']) console.log(key, path[key]('/a/b.txt'));
|