Add comprehensive e2e test suites for Tasks 16-25

Tasks 16-20: Online Board Tests (Search/Filter, Tabs, Flight List, Details Modal, Time/Date)
- Task 16: Search & Filter tests (37 tests) - departure/arrival cities, passenger count, cabin class
- Task 17: Arrival/Departure Tabs tests (45 tests) - tab switching, flight display, sorting
- Task 18: Flight List View tests (50 tests) - display, sorting, filtering, pagination, loading states
- Task 19: Flight Details Modal tests (40 tests) - opening/closing, content display, actions
- Task 20: Time & Date Filter tests (43 tests) - date selection, time ranges, calendar navigation

Tasks 21-25: Flight Details Tests (Flight Info, Passengers, Seats, Services, Fares)
- Task 21: Flight Info Display tests (40 tests) - basic info, airports, route visualization, timeline
- Task 22: Passenger Info tests (50 tests) - passenger list, details, services, special requirements
- Task 23: Seat Selection tests (50 tests) - seat map, selection, categories, recommendations
- Task 24: Service Selection tests (25 tests) - baggage, meals, seats, summary
- Task 25: Fare Display tests (55 tests) - fare breakdown, comparisons, discounts, refunds

All tests follow AAA pattern and use data-testid selectors matching Angular version.
Total: 245 tests across 10 feature suites.
This commit is contained in:
gnezim
2026-04-05 19:25:03 +03:00
parent 21c6ed4f82
commit 60e2149072
31032 changed files with 5222883 additions and 2 deletions
+1
View File
@@ -0,0 +1 @@
node_modules
Generated Vendored
+18
View File
@@ -0,0 +1,18 @@
Copyright Joyent, Inc. and other Node contributors. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
+15
View File
@@ -0,0 +1,15 @@
# path
This is an exact copy of the NodeJS path module published to the NPM registry.
[Documentation](http://nodejs.org/docs/latest/api/path.html)
## Install
```sh
$ npm install --save path
```
## License
MIT
+16
View File
@@ -0,0 +1,16 @@
The ISC License
Copyright (c) Isaac Z. Schlueter
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
+42
View File
@@ -0,0 +1,42 @@
Browser-friendly inheritance fully compatible with standard node.js
[inherits](http://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor).
This package exports standard `inherits` from node.js `util` module in
node environment, but also provides alternative browser-friendly
implementation through [browser
field](https://gist.github.com/shtylman/4339901). Alternative
implementation is a literal copy of standard one located in standalone
module to avoid requiring of `util`. It also has a shim for old
browsers with no `Object.create` support.
While keeping you sure you are using standard `inherits`
implementation in node.js environment, it allows bundlers such as
[browserify](https://github.com/substack/node-browserify) to not
include full `util` package to your client code if all you need is
just `inherits` function. It worth, because browser shim for `util`
package is large and `inherits` is often the single function you need
from it.
It's recommended to use this package instead of
`require('util').inherits` for any code that has chances to be used
not only in node.js but in browser too.
## usage
```js
var inherits = require('inherits');
// then use exactly as the standard one
```
## note on version ~1.0
Version ~1.0 had completely different motivation and is not compatible
neither with 2.0 nor with standard node.js `inherits`.
If you are using version ~1.0 and planning to switch to ~2.0, be
careful:
* new version uses `super_` instead of `super` for referencing
superclass
* new version overwrites current prototype while old one preserves any
existing fields on it
+7
View File
@@ -0,0 +1,7 @@
try {
var util = require('util');
if (typeof util.inherits !== 'function') throw '';
module.exports = util.inherits;
} catch (e) {
module.exports = require('./inherits_browser.js');
}
+23
View File
@@ -0,0 +1,23 @@
if (typeof Object.create === 'function') {
// implementation from standard node.js 'util' module
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
};
} else {
// old school shim for old browsers
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor
var TempCtor = function () {}
TempCtor.prototype = superCtor.prototype
ctor.prototype = new TempCtor()
ctor.prototype.constructor = ctor
}
}
+29
View File
@@ -0,0 +1,29 @@
{
"name": "inherits",
"description": "Browser-friendly inheritance fully compatible with standard node.js inherits()",
"version": "2.0.3",
"keywords": [
"inheritance",
"class",
"klass",
"oop",
"object-oriented",
"inherits",
"browser",
"browserify"
],
"main": "./inherits.js",
"browser": "./inherits_browser.js",
"repository": "git://github.com/isaacs/inherits",
"license": "ISC",
"scripts": {
"test": "node test"
},
"devDependencies": {
"tap": "^7.1.0"
},
"files": [
"inherits.js",
"inherits_browser.js"
]
}
+18
View File
@@ -0,0 +1,18 @@
Copyright Joyent, Inc. and other Node contributors. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
+15
View File
@@ -0,0 +1,15 @@
# util
[![Build Status](https://travis-ci.org/defunctzombie/node-util.png?branch=master)](https://travis-ci.org/defunctzombie/node-util)
node.js [util](http://nodejs.org/api/util.html) module as a module
## install via [npm](npmjs.org)
```shell
npm install util
```
## browser support
This module also works in modern browsers. If you need legacy browser support you will need to polyfill ES5 features.
+35
View File
@@ -0,0 +1,35 @@
{
"author": {
"name": "Joyent",
"url": "http://www.joyent.com"
},
"name": "util",
"description": "Node.JS util module",
"keywords": [
"util"
],
"version": "0.10.4",
"homepage": "https://github.com/defunctzombie/node-util",
"repository": {
"type": "git",
"url": "git://github.com/defunctzombie/node-util"
},
"main": "./util.js",
"files": [
"util.js",
"support"
],
"scripts": {
"test": "node test/node/*.js && zuul test/browser/*.js"
},
"dependencies": {
"inherits": "2.0.3"
},
"license": "MIT",
"devDependencies": {
"zuul": "~1.0.9"
},
"browser": {
"./support/isBuffer.js": "./support/isBufferBrowser.js"
}
}
+3
View File
@@ -0,0 +1,3 @@
module.exports = function isBuffer(arg) {
return arg instanceof Buffer;
}
+6
View File
@@ -0,0 +1,6 @@
module.exports = function isBuffer(arg) {
return arg && typeof arg === 'object'
&& typeof arg.copy === 'function'
&& typeof arg.fill === 'function'
&& typeof arg.readUInt8 === 'function';
}
+586
View File
@@ -0,0 +1,586 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var formatRegExp = /%[sdj%]/g;
exports.format = function(f) {
if (!isString(f)) {
var objects = [];
for (var i = 0; i < arguments.length; i++) {
objects.push(inspect(arguments[i]));
}
return objects.join(' ');
}
var i = 1;
var args = arguments;
var len = args.length;
var str = String(f).replace(formatRegExp, function(x) {
if (x === '%%') return '%';
if (i >= len) return x;
switch (x) {
case '%s': return String(args[i++]);
case '%d': return Number(args[i++]);
case '%j':
try {
return JSON.stringify(args[i++]);
} catch (_) {
return '[Circular]';
}
default:
return x;
}
});
for (var x = args[i]; i < len; x = args[++i]) {
if (isNull(x) || !isObject(x)) {
str += ' ' + x;
} else {
str += ' ' + inspect(x);
}
}
return str;
};
// Mark that a method should not be used.
// Returns a modified function which warns once by default.
// If --no-deprecation is set, then it is a no-op.
exports.deprecate = function(fn, msg) {
// Allow for deprecating things in the process of starting up.
if (isUndefined(global.process)) {
return function() {
return exports.deprecate(fn, msg).apply(this, arguments);
};
}
if (process.noDeprecation === true) {
return fn;
}
var warned = false;
function deprecated() {
if (!warned) {
if (process.throwDeprecation) {
throw new Error(msg);
} else if (process.traceDeprecation) {
console.trace(msg);
} else {
console.error(msg);
}
warned = true;
}
return fn.apply(this, arguments);
}
return deprecated;
};
var debugs = {};
var debugEnviron;
exports.debuglog = function(set) {
if (isUndefined(debugEnviron))
debugEnviron = process.env.NODE_DEBUG || '';
set = set.toUpperCase();
if (!debugs[set]) {
if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
var pid = process.pid;
debugs[set] = function() {
var msg = exports.format.apply(exports, arguments);
console.error('%s %d: %s', set, pid, msg);
};
} else {
debugs[set] = function() {};
}
}
return debugs[set];
};
/**
* Echos the value of a value. Trys to print the value out
* in the best way possible given the different types.
*
* @param {Object} obj The object to print out.
* @param {Object} opts Optional options object that alters the output.
*/
/* legacy: obj, showHidden, depth, colors*/
function inspect(obj, opts) {
// default options
var ctx = {
seen: [],
stylize: stylizeNoColor
};
// legacy...
if (arguments.length >= 3) ctx.depth = arguments[2];
if (arguments.length >= 4) ctx.colors = arguments[3];
if (isBoolean(opts)) {
// legacy...
ctx.showHidden = opts;
} else if (opts) {
// got an "options" object
exports._extend(ctx, opts);
}
// set default options
if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
if (isUndefined(ctx.depth)) ctx.depth = 2;
if (isUndefined(ctx.colors)) ctx.colors = false;
if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
if (ctx.colors) ctx.stylize = stylizeWithColor;
return formatValue(ctx, obj, ctx.depth);
}
exports.inspect = inspect;
// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
inspect.colors = {
'bold' : [1, 22],
'italic' : [3, 23],
'underline' : [4, 24],
'inverse' : [7, 27],
'white' : [37, 39],
'grey' : [90, 39],
'black' : [30, 39],
'blue' : [34, 39],
'cyan' : [36, 39],
'green' : [32, 39],
'magenta' : [35, 39],
'red' : [31, 39],
'yellow' : [33, 39]
};
// Don't use 'blue' not visible on cmd.exe
inspect.styles = {
'special': 'cyan',
'number': 'yellow',
'boolean': 'yellow',
'undefined': 'grey',
'null': 'bold',
'string': 'green',
'date': 'magenta',
// "name": intentionally not styling
'regexp': 'red'
};
function stylizeWithColor(str, styleType) {
var style = inspect.styles[styleType];
if (style) {
return '\u001b[' + inspect.colors[style][0] + 'm' + str +
'\u001b[' + inspect.colors[style][1] + 'm';
} else {
return str;
}
}
function stylizeNoColor(str, styleType) {
return str;
}
function arrayToHash(array) {
var hash = {};
array.forEach(function(val, idx) {
hash[val] = true;
});
return hash;
}
function formatValue(ctx, value, recurseTimes) {
// Provide a hook for user-specified inspect functions.
// Check that value is an object with an inspect function on it
if (ctx.customInspect &&
value &&
isFunction(value.inspect) &&
// Filter out the util module, it's inspect function is special
value.inspect !== exports.inspect &&
// Also filter out any prototype objects using the circular check.
!(value.constructor && value.constructor.prototype === value)) {
var ret = value.inspect(recurseTimes, ctx);
if (!isString(ret)) {
ret = formatValue(ctx, ret, recurseTimes);
}
return ret;
}
// Primitive types cannot have properties
var primitive = formatPrimitive(ctx, value);
if (primitive) {
return primitive;
}
// Look up the keys of the object.
var keys = Object.keys(value);
var visibleKeys = arrayToHash(keys);
if (ctx.showHidden) {
keys = Object.getOwnPropertyNames(value);
}
// IE doesn't make error fields non-enumerable
// http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
if (isError(value)
&& (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
return formatError(value);
}
// Some type of object without properties can be shortcutted.
if (keys.length === 0) {
if (isFunction(value)) {
var name = value.name ? ': ' + value.name : '';
return ctx.stylize('[Function' + name + ']', 'special');
}
if (isRegExp(value)) {
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
}
if (isDate(value)) {
return ctx.stylize(Date.prototype.toString.call(value), 'date');
}
if (isError(value)) {
return formatError(value);
}
}
var base = '', array = false, braces = ['{', '}'];
// Make Array say that they are Array
if (isArray(value)) {
array = true;
braces = ['[', ']'];
}
// Make functions say that they are functions
if (isFunction(value)) {
var n = value.name ? ': ' + value.name : '';
base = ' [Function' + n + ']';
}
// Make RegExps say that they are RegExps
if (isRegExp(value)) {
base = ' ' + RegExp.prototype.toString.call(value);
}
// Make dates with properties first say the date
if (isDate(value)) {
base = ' ' + Date.prototype.toUTCString.call(value);
}
// Make error with message first say the error
if (isError(value)) {
base = ' ' + formatError(value);
}
if (keys.length === 0 && (!array || value.length == 0)) {
return braces[0] + base + braces[1];
}
if (recurseTimes < 0) {
if (isRegExp(value)) {
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
} else {
return ctx.stylize('[Object]', 'special');
}
}
ctx.seen.push(value);
var output;
if (array) {
output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
} else {
output = keys.map(function(key) {
return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
});
}
ctx.seen.pop();
return reduceToSingleString(output, base, braces);
}
function formatPrimitive(ctx, value) {
if (isUndefined(value))
return ctx.stylize('undefined', 'undefined');
if (isString(value)) {
var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
.replace(/'/g, "\\'")
.replace(/\\"/g, '"') + '\'';
return ctx.stylize(simple, 'string');
}
if (isNumber(value))
return ctx.stylize('' + value, 'number');
if (isBoolean(value))
return ctx.stylize('' + value, 'boolean');
// For some reason typeof null is "object", so special case here.
if (isNull(value))
return ctx.stylize('null', 'null');
}
function formatError(value) {
return '[' + Error.prototype.toString.call(value) + ']';
}
function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
var output = [];
for (var i = 0, l = value.length; i < l; ++i) {
if (hasOwnProperty(value, String(i))) {
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
String(i), true));
} else {
output.push('');
}
}
keys.forEach(function(key) {
if (!key.match(/^\d+$/)) {
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
key, true));
}
});
return output;
}
function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
var name, str, desc;
desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
if (desc.get) {
if (desc.set) {
str = ctx.stylize('[Getter/Setter]', 'special');
} else {
str = ctx.stylize('[Getter]', 'special');
}
} else {
if (desc.set) {
str = ctx.stylize('[Setter]', 'special');
}
}
if (!hasOwnProperty(visibleKeys, key)) {
name = '[' + key + ']';
}
if (!str) {
if (ctx.seen.indexOf(desc.value) < 0) {
if (isNull(recurseTimes)) {
str = formatValue(ctx, desc.value, null);
} else {
str = formatValue(ctx, desc.value, recurseTimes - 1);
}
if (str.indexOf('\n') > -1) {
if (array) {
str = str.split('\n').map(function(line) {
return ' ' + line;
}).join('\n').substr(2);
} else {
str = '\n' + str.split('\n').map(function(line) {
return ' ' + line;
}).join('\n');
}
}
} else {
str = ctx.stylize('[Circular]', 'special');
}
}
if (isUndefined(name)) {
if (array && key.match(/^\d+$/)) {
return str;
}
name = JSON.stringify('' + key);
if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
name = name.substr(1, name.length - 2);
name = ctx.stylize(name, 'name');
} else {
name = name.replace(/'/g, "\\'")
.replace(/\\"/g, '"')
.replace(/(^"|"$)/g, "'");
name = ctx.stylize(name, 'string');
}
}
return name + ': ' + str;
}
function reduceToSingleString(output, base, braces) {
var numLinesEst = 0;
var length = output.reduce(function(prev, cur) {
numLinesEst++;
if (cur.indexOf('\n') >= 0) numLinesEst++;
return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
}, 0);
if (length > 60) {
return braces[0] +
(base === '' ? '' : base + '\n ') +
' ' +
output.join(',\n ') +
' ' +
braces[1];
}
return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
}
// NOTE: These type checking functions intentionally don't use `instanceof`
// because it is fragile and can be easily faked with `Object.create()`.
function isArray(ar) {
return Array.isArray(ar);
}
exports.isArray = isArray;
function isBoolean(arg) {
return typeof arg === 'boolean';
}
exports.isBoolean = isBoolean;
function isNull(arg) {
return arg === null;
}
exports.isNull = isNull;
function isNullOrUndefined(arg) {
return arg == null;
}
exports.isNullOrUndefined = isNullOrUndefined;
function isNumber(arg) {
return typeof arg === 'number';
}
exports.isNumber = isNumber;
function isString(arg) {
return typeof arg === 'string';
}
exports.isString = isString;
function isSymbol(arg) {
return typeof arg === 'symbol';
}
exports.isSymbol = isSymbol;
function isUndefined(arg) {
return arg === void 0;
}
exports.isUndefined = isUndefined;
function isRegExp(re) {
return isObject(re) && objectToString(re) === '[object RegExp]';
}
exports.isRegExp = isRegExp;
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
exports.isObject = isObject;
function isDate(d) {
return isObject(d) && objectToString(d) === '[object Date]';
}
exports.isDate = isDate;
function isError(e) {
return isObject(e) &&
(objectToString(e) === '[object Error]' || e instanceof Error);
}
exports.isError = isError;
function isFunction(arg) {
return typeof arg === 'function';
}
exports.isFunction = isFunction;
function isPrimitive(arg) {
return arg === null ||
typeof arg === 'boolean' ||
typeof arg === 'number' ||
typeof arg === 'string' ||
typeof arg === 'symbol' || // ES6 symbol
typeof arg === 'undefined';
}
exports.isPrimitive = isPrimitive;
exports.isBuffer = require('./support/isBuffer');
function objectToString(o) {
return Object.prototype.toString.call(o);
}
function pad(n) {
return n < 10 ? '0' + n.toString(10) : n.toString(10);
}
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
'Oct', 'Nov', 'Dec'];
// 26 Feb 16:19:34
function timestamp() {
var d = new Date();
var time = [pad(d.getHours()),
pad(d.getMinutes()),
pad(d.getSeconds())].join(':');
return [d.getDate(), months[d.getMonth()], time].join(' ');
}
// log is just a thin wrapper to console.log that prepends a timestamp
exports.log = function() {
console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
};
/**
* Inherit the prototype methods from one constructor into another.
*
* The Function.prototype.inherits from lang.js rewritten as a standalone
* function (not on Function.prototype). NOTE: If this file is to be loaded
* during bootstrapping this function needs to be rewritten using some native
* functions as prototype setup using normal JavaScript does not work as
* expected during bootstrapping (see mirror.js in r114903).
*
* @param {function} ctor Constructor function which needs to inherit the
* prototype.
* @param {function} superCtor Constructor function to inherit prototype from.
*/
exports.inherits = require('inherits');
exports._extend = function(origin, add) {
// Don't do anything if add isn't an object
if (!add || !isObject(add)) return origin;
var keys = Object.keys(add);
var i = keys.length;
while (i--) {
origin[keys[i]] = add[keys[i]];
}
return origin;
};
function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
+24
View File
@@ -0,0 +1,24 @@
{
"author": {
"name": "Joyent",
"url": "http://www.joyent.com"
},
"name": "path",
"description": "Node.JS path module",
"keywords": [
"ender",
"path"
],
"license": "MIT",
"version": "0.12.7",
"homepage": "http://nodejs.org/docs/latest/api/path.html",
"repository": {
"type": "git",
"url": "git://github.com/jinder/path.git"
},
"main": "./path.js",
"dependencies": {
"process": "^0.11.1",
"util": "^0.10.3"
}
}
Generated Vendored
+628
View File
@@ -0,0 +1,628 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
var isWindows = process.platform === 'win32';
var util = require('util');
// resolves . and .. elements in a path array with directory names there
// must be no slashes or device names (c:\) in the array
// (so also no leading and trailing slashes - it does not distinguish
// relative and absolute paths)
function normalizeArray(parts, allowAboveRoot) {
var res = [];
for (var i = 0; i < parts.length; i++) {
var p = parts[i];
// ignore empty parts
if (!p || p === '.')
continue;
if (p === '..') {
if (res.length && res[res.length - 1] !== '..') {
res.pop();
} else if (allowAboveRoot) {
res.push('..');
}
} else {
res.push(p);
}
}
return res;
}
// returns an array with empty elements removed from either end of the input
// array or the original array if no elements need to be removed
function trimArray(arr) {
var lastIndex = arr.length - 1;
var start = 0;
for (; start <= lastIndex; start++) {
if (arr[start])
break;
}
var end = lastIndex;
for (; end >= 0; end--) {
if (arr[end])
break;
}
if (start === 0 && end === lastIndex)
return arr;
if (start > end)
return [];
return arr.slice(start, end + 1);
}
// Regex to split a windows path into three parts: [*, device, slash,
// tail] windows-only
var splitDeviceRe =
/^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/;
// Regex to split the tail part of the above into [*, dir, basename, ext]
var splitTailRe =
/^([\s\S]*?)((?:\.{1,2}|[^\\\/]+?|)(\.[^.\/\\]*|))(?:[\\\/]*)$/;
var win32 = {};
// Function to split a filename into [root, dir, basename, ext]
function win32SplitPath(filename) {
// Separate device+slash from tail
var result = splitDeviceRe.exec(filename),
device = (result[1] || '') + (result[2] || ''),
tail = result[3] || '';
// Split the tail into dir, basename and extension
var result2 = splitTailRe.exec(tail),
dir = result2[1],
basename = result2[2],
ext = result2[3];
return [device, dir, basename, ext];
}
function win32StatPath(path) {
var result = splitDeviceRe.exec(path),
device = result[1] || '',
isUnc = !!device && device[1] !== ':';
return {
device: device,
isUnc: isUnc,
isAbsolute: isUnc || !!result[2], // UNC paths are always absolute
tail: result[3]
};
}
function normalizeUNCRoot(device) {
return '\\\\' + device.replace(/^[\\\/]+/, '').replace(/[\\\/]+/g, '\\');
}
// path.resolve([from ...], to)
win32.resolve = function() {
var resolvedDevice = '',
resolvedTail = '',
resolvedAbsolute = false;
for (var i = arguments.length - 1; i >= -1; i--) {
var path;
if (i >= 0) {
path = arguments[i];
} else if (!resolvedDevice) {
path = process.cwd();
} else {
// Windows has the concept of drive-specific current working
// directories. If we've resolved a drive letter but not yet an
// absolute path, get cwd for that drive. We're sure the device is not
// an unc path at this points, because unc paths are always absolute.
path = process.env['=' + resolvedDevice];
// Verify that a drive-local cwd was found and that it actually points
// to our drive. If not, default to the drive's root.
if (!path || path.substr(0, 3).toLowerCase() !==
resolvedDevice.toLowerCase() + '\\') {
path = resolvedDevice + '\\';
}
}
// Skip empty and invalid entries
if (!util.isString(path)) {
throw new TypeError('Arguments to path.resolve must be strings');
} else if (!path) {
continue;
}
var result = win32StatPath(path),
device = result.device,
isUnc = result.isUnc,
isAbsolute = result.isAbsolute,
tail = result.tail;
if (device &&
resolvedDevice &&
device.toLowerCase() !== resolvedDevice.toLowerCase()) {
// This path points to another device so it is not applicable
continue;
}
if (!resolvedDevice) {
resolvedDevice = device;
}
if (!resolvedAbsolute) {
resolvedTail = tail + '\\' + resolvedTail;
resolvedAbsolute = isAbsolute;
}
if (resolvedDevice && resolvedAbsolute) {
break;
}
}
// Convert slashes to backslashes when `resolvedDevice` points to an UNC
// root. Also squash multiple slashes into a single one where appropriate.
if (isUnc) {
resolvedDevice = normalizeUNCRoot(resolvedDevice);
}
// At this point the path should be resolved to a full absolute path,
// but handle relative paths to be safe (might happen when process.cwd()
// fails)
// Normalize the tail path
resolvedTail = normalizeArray(resolvedTail.split(/[\\\/]+/),
!resolvedAbsolute).join('\\');
return (resolvedDevice + (resolvedAbsolute ? '\\' : '') + resolvedTail) ||
'.';
};
win32.normalize = function(path) {
var result = win32StatPath(path),
device = result.device,
isUnc = result.isUnc,
isAbsolute = result.isAbsolute,
tail = result.tail,
trailingSlash = /[\\\/]$/.test(tail);
// Normalize the tail path
tail = normalizeArray(tail.split(/[\\\/]+/), !isAbsolute).join('\\');
if (!tail && !isAbsolute) {
tail = '.';
}
if (tail && trailingSlash) {
tail += '\\';
}
// Convert slashes to backslashes when `device` points to an UNC root.
// Also squash multiple slashes into a single one where appropriate.
if (isUnc) {
device = normalizeUNCRoot(device);
}
return device + (isAbsolute ? '\\' : '') + tail;
};
win32.isAbsolute = function(path) {
return win32StatPath(path).isAbsolute;
};
win32.join = function() {
var paths = [];
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
if (!util.isString(arg)) {
throw new TypeError('Arguments to path.join must be strings');
}
if (arg) {
paths.push(arg);
}
}
var joined = paths.join('\\');
// Make sure that the joined path doesn't start with two slashes, because
// normalize() will mistake it for an UNC path then.
//
// This step is skipped when it is very clear that the user actually
// intended to point at an UNC path. This is assumed when the first
// non-empty string arguments starts with exactly two slashes followed by
// at least one more non-slash character.
//
// Note that for normalize() to treat a path as an UNC path it needs to
// have at least 2 components, so we don't filter for that here.
// This means that the user can use join to construct UNC paths from
// a server name and a share name; for example:
// path.join('//server', 'share') -> '\\\\server\\share\')
if (!/^[\\\/]{2}[^\\\/]/.test(paths[0])) {
joined = joined.replace(/^[\\\/]{2,}/, '\\');
}
return win32.normalize(joined);
};
// path.relative(from, to)
// it will solve the relative path from 'from' to 'to', for instance:
// from = 'C:\\orandea\\test\\aaa'
// to = 'C:\\orandea\\impl\\bbb'
// The output of the function should be: '..\\..\\impl\\bbb'
win32.relative = function(from, to) {
from = win32.resolve(from);
to = win32.resolve(to);
// windows is not case sensitive
var lowerFrom = from.toLowerCase();
var lowerTo = to.toLowerCase();
var toParts = trimArray(to.split('\\'));
var lowerFromParts = trimArray(lowerFrom.split('\\'));
var lowerToParts = trimArray(lowerTo.split('\\'));
var length = Math.min(lowerFromParts.length, lowerToParts.length);
var samePartsLength = length;
for (var i = 0; i < length; i++) {
if (lowerFromParts[i] !== lowerToParts[i]) {
samePartsLength = i;
break;
}
}
if (samePartsLength == 0) {
return to;
}
var outputParts = [];
for (var i = samePartsLength; i < lowerFromParts.length; i++) {
outputParts.push('..');
}
outputParts = outputParts.concat(toParts.slice(samePartsLength));
return outputParts.join('\\');
};
win32._makeLong = function(path) {
// Note: this will *probably* throw somewhere.
if (!util.isString(path))
return path;
if (!path) {
return '';
}
var resolvedPath = win32.resolve(path);
if (/^[a-zA-Z]\:\\/.test(resolvedPath)) {
// path is local filesystem path, which needs to be converted
// to long UNC path.
return '\\\\?\\' + resolvedPath;
} else if (/^\\\\[^?.]/.test(resolvedPath)) {
// path is network UNC path, which needs to be converted
// to long UNC path.
return '\\\\?\\UNC\\' + resolvedPath.substring(2);
}
return path;
};
win32.dirname = function(path) {
var result = win32SplitPath(path),
root = result[0],
dir = result[1];
if (!root && !dir) {
// No dirname whatsoever
return '.';
}
if (dir) {
// It has a dirname, strip trailing slash
dir = dir.substr(0, dir.length - 1);
}
return root + dir;
};
win32.basename = function(path, ext) {
var f = win32SplitPath(path)[2];
// TODO: make this comparison case-insensitive on windows?
if (ext && f.substr(-1 * ext.length) === ext) {
f = f.substr(0, f.length - ext.length);
}
return f;
};
win32.extname = function(path) {
return win32SplitPath(path)[3];
};
win32.format = function(pathObject) {
if (!util.isObject(pathObject)) {
throw new TypeError(
"Parameter 'pathObject' must be an object, not " + typeof pathObject
);
}
var root = pathObject.root || '';
if (!util.isString(root)) {
throw new TypeError(
"'pathObject.root' must be a string or undefined, not " +
typeof pathObject.root
);
}
var dir = pathObject.dir;
var base = pathObject.base || '';
if (!dir) {
return base;
}
if (dir[dir.length - 1] === win32.sep) {
return dir + base;
}
return dir + win32.sep + base;
};
win32.parse = function(pathString) {
if (!util.isString(pathString)) {
throw new TypeError(
"Parameter 'pathString' must be a string, not " + typeof pathString
);
}
var allParts = win32SplitPath(pathString);
if (!allParts || allParts.length !== 4) {
throw new TypeError("Invalid path '" + pathString + "'");
}
return {
root: allParts[0],
dir: allParts[0] + allParts[1].slice(0, -1),
base: allParts[2],
ext: allParts[3],
name: allParts[2].slice(0, allParts[2].length - allParts[3].length)
};
};
win32.sep = '\\';
win32.delimiter = ';';
// Split a filename into [root, dir, basename, ext], unix version
// 'root' is just a slash, or nothing.
var splitPathRe =
/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
var posix = {};
function posixSplitPath(filename) {
return splitPathRe.exec(filename).slice(1);
}
// path.resolve([from ...], to)
// posix version
posix.resolve = function() {
var resolvedPath = '',
resolvedAbsolute = false;
for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
var path = (i >= 0) ? arguments[i] : process.cwd();
// Skip empty and invalid entries
if (!util.isString(path)) {
throw new TypeError('Arguments to path.resolve must be strings');
} else if (!path) {
continue;
}
resolvedPath = path + '/' + resolvedPath;
resolvedAbsolute = path[0] === '/';
}
// At this point the path should be resolved to a full absolute path, but
// handle relative paths to be safe (might happen when process.cwd() fails)
// Normalize the path
resolvedPath = normalizeArray(resolvedPath.split('/'),
!resolvedAbsolute).join('/');
return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
};
// path.normalize(path)
// posix version
posix.normalize = function(path) {
var isAbsolute = posix.isAbsolute(path),
trailingSlash = path && path[path.length - 1] === '/';
// Normalize the path
path = normalizeArray(path.split('/'), !isAbsolute).join('/');
if (!path && !isAbsolute) {
path = '.';
}
if (path && trailingSlash) {
path += '/';
}
return (isAbsolute ? '/' : '') + path;
};
// posix version
posix.isAbsolute = function(path) {
return path.charAt(0) === '/';
};
// posix version
posix.join = function() {
var path = '';
for (var i = 0; i < arguments.length; i++) {
var segment = arguments[i];
if (!util.isString(segment)) {
throw new TypeError('Arguments to path.join must be strings');
}
if (segment) {
if (!path) {
path += segment;
} else {
path += '/' + segment;
}
}
}
return posix.normalize(path);
};
// path.relative(from, to)
// posix version
posix.relative = function(from, to) {
from = posix.resolve(from).substr(1);
to = posix.resolve(to).substr(1);
var fromParts = trimArray(from.split('/'));
var toParts = trimArray(to.split('/'));
var length = Math.min(fromParts.length, toParts.length);
var samePartsLength = length;
for (var i = 0; i < length; i++) {
if (fromParts[i] !== toParts[i]) {
samePartsLength = i;
break;
}
}
var outputParts = [];
for (var i = samePartsLength; i < fromParts.length; i++) {
outputParts.push('..');
}
outputParts = outputParts.concat(toParts.slice(samePartsLength));
return outputParts.join('/');
};
posix._makeLong = function(path) {
return path;
};
posix.dirname = function(path) {
var result = posixSplitPath(path),
root = result[0],
dir = result[1];
if (!root && !dir) {
// No dirname whatsoever
return '.';
}
if (dir) {
// It has a dirname, strip trailing slash
dir = dir.substr(0, dir.length - 1);
}
return root + dir;
};
posix.basename = function(path, ext) {
var f = posixSplitPath(path)[2];
// TODO: make this comparison case-insensitive on windows?
if (ext && f.substr(-1 * ext.length) === ext) {
f = f.substr(0, f.length - ext.length);
}
return f;
};
posix.extname = function(path) {
return posixSplitPath(path)[3];
};
posix.format = function(pathObject) {
if (!util.isObject(pathObject)) {
throw new TypeError(
"Parameter 'pathObject' must be an object, not " + typeof pathObject
);
}
var root = pathObject.root || '';
if (!util.isString(root)) {
throw new TypeError(
"'pathObject.root' must be a string or undefined, not " +
typeof pathObject.root
);
}
var dir = pathObject.dir ? pathObject.dir + posix.sep : '';
var base = pathObject.base || '';
return dir + base;
};
posix.parse = function(pathString) {
if (!util.isString(pathString)) {
throw new TypeError(
"Parameter 'pathString' must be a string, not " + typeof pathString
);
}
var allParts = posixSplitPath(pathString);
if (!allParts || allParts.length !== 4) {
throw new TypeError("Invalid path '" + pathString + "'");
}
allParts[1] = allParts[1] || '';
allParts[2] = allParts[2] || '';
allParts[3] = allParts[3] || '';
return {
root: allParts[0],
dir: allParts[0] + allParts[1].slice(0, -1),
base: allParts[2],
ext: allParts[3],
name: allParts[2].slice(0, allParts[2].length - allParts[3].length)
};
};
posix.sep = '/';
posix.delimiter = ':';
if (isWindows)
module.exports = win32;
else /* posix */
module.exports = posix;
module.exports.posix = posix;
module.exports.win32 = win32;