Skip to content

Commit

Permalink
feat: add a few utils (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
billiegoose authored Jul 2, 2019
1 parent 2bd3b5e commit 75c224b
Show file tree
Hide file tree
Showing 32 changed files with 846 additions and 19 deletions.
1 change: 1 addition & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ jobs:
name: cc-before
command: |
./cc-test-reporter before-build
- run: yarn build
- run: yarn test.prod
- run:
name: cc-after
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@
*.log*
*-debug.log*
*-error.log*
src/grammar.js
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"node": ">=10"
},
"scripts": {
"build": "sl-scripts build",
"build": "pegjs --optimize size src/grammar.pegjs && sl-scripts build",
"commit": "git-cz",
"lint": "tslint -c tslint.json 'src/**/*.ts?'",
"lint.fix": "yarn lint --fix",
Expand All @@ -41,7 +41,9 @@
"@types/jest": "24.x.x",
"jest": "24.x.x",
"nodemon": "1.x.x",
"pegjs": "^0.10.0",
"prettier": "1.x.x",
"rollup-plugin-commonjs": "^10.0.1",
"ts-jest": "24.x.x",
"tslint": "5.17.0",
"tslint-config-prettier": "1.18.x",
Expand Down
7 changes: 6 additions & 1 deletion rollup.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import config from '@stoplight/scripts/rollup.config';

export default config; // you can customize your Rollup configuration here
// We need to add commonjs support to import 'grammar.js' generated by PEG.js
import commonjs from 'rollup-plugin-commonjs';

config.plugins.push(commonjs())

export default config;
58 changes: 58 additions & 0 deletions src/__tests__/dirname.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { dirname } from '../dirname';

describe('posix dirname', () => {
it.each`
path | expected
${'/a/b/'} | ${'/a'}
${'/a/b'} | ${'/a'}
${'/a'} | ${'/'}
${''} | ${'.'}
${'/'} | ${'/'}
${'////'} | ${'/'}
${'//a'} | ${'/'}
${'foo'} | ${'.'}
`('computes dirname of $path', ({ path, expected }) => {
expect(dirname(path)).toBe(expected);
});
});

describe('win32 dirname', () => {
it.each`
path | expected
${'c:\\'} | ${'c:/'}
${'c:\\foo'} | ${'c:/'}
${'c:\\foo\\'} | ${'c:/'}
${'c:\\foo\\bar'} | ${'c:/foo'}
${'c:\\foo\\bar\\'} | ${'c:/foo'}
${'c:\\foo\\bar\\baz'} | ${'c:/foo/bar'}
${'\\'} | ${'/'}
${'\\foo'} | ${'/'}
${'\\foo\\'} | ${'/'}
${'\\foo\\bar'} | ${'/foo'}
${'\\foo\\bar\\'} | ${'/foo'}
${'\\foo\\bar\\baz'} | ${'/foo/bar'}
${'c:'} | ${'.'}
${'c:foo'} | ${'.'}
${'c:foo\\'} | ${'.'}
${'c:foo\\bar'} | ${'c:foo'}
${'c:foo\\bar\\'} | ${'c:foo'}
${'c:foo\\bar\\baz'} | ${'c:foo/bar'}
${'file:stream'} | ${'.'}
${'dir\\file:stream'} | ${'dir'}
${'\\\\unc\\share'} | ${'/unc'}
${'\\\\unc\\share\\foo'} | ${'/unc/share'}
${'\\\\unc\\share\\foo\\'} | ${'/unc/share'}
${'\\\\unc\\share\\foo\\bar'} | ${'/unc/share/foo'}
${'\\\\unc\\share\\foo\\bar\\'} | ${'/unc/share/foo'}
${'\\\\unc\\share\\foo\\bar\\baz'} | ${'/unc/share/foo/bar'}
${'/a/b/'} | ${'/a'}
${'/a/b'} | ${'/a'}
${'/a'} | ${'/'}
${''} | ${'.'}
${'/'} | ${'/'}
${'////'} | ${'/'}
${'foo'} | ${'.'}
`('computes dirname of $path', ({ path, expected }) => {
expect(dirname(path)).toBe(expected);
});
});
52 changes: 52 additions & 0 deletions src/__tests__/extname.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { extname } from '../extname';

describe('extname', () => {
it.each`
path | expected
${__filename} | ${'.ts'}
${''} | ${''}
${'/path/to/file'} | ${''}
${'/path/to/file.ext'} | ${'.ext'}
${'/path.to/file.ext'} | ${'.ext'}
${'/path.to/file'} | ${''}
${'/path.to/.file'} | ${''}
${'/path.to/.file.ext'} | ${'.ext'}
${'/path/to/f.ext'} | ${'.ext'}
${'/path/to/..ext'} | ${'.ext'}
${'/path/to/..'} | ${''}
${'file'} | ${''}
${'file.ext'} | ${'.ext'}
${'.file'} | ${''}
${'.file.ext'} | ${'.ext'}
${'/file'} | ${''}
${'/file.ext'} | ${'.ext'}
${'/.file'} | ${''}
${'/.file.ext'} | ${'.ext'}
${'.path/file.ext'} | ${'.ext'}
${'file.ext.ext'} | ${'.ext'}
${'file.'} | ${'.'}
${'.'} | ${''}
${'./'} | ${''}
${'.file.ext'} | ${'.ext'}
${'.file'} | ${''}
${'.file.'} | ${'.'}
${'.file..'} | ${'.'}
${'..'} | ${''}
${'../'} | ${''}
${'..file.ext'} | ${'.ext'}
${'..file'} | ${'.file'}
${'..file.'} | ${'.'}
${'..file..'} | ${'.'}
${'...'} | ${'.'}
${'...ext'} | ${'.ext'}
${'....'} | ${'.'}
${'file.ext/'} | ${'.ext'}
${'file.ext//'} | ${'.ext'}
${'file/'} | ${''}
${'file//'} | ${''}
${'file./'} | ${'.'}
${'file.//'} | ${'.'}
`('computes extname of $path', ({ path, expected }) => {
expect(extname(path)).toBe(expected);
});
});
26 changes: 26 additions & 0 deletions src/__tests__/isAbsolute.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { isAbsolute } from '../isAbsolute';

describe('isAbsolute', () => {
it.each([
'\\foo\\bar.json',
'c:\\foo\\bar.json',
'c:\\',
'c:/',
'c:/foo/bar.json',
'/home/test',
'/',
'//',
'/var/lib/test/',
'/var/bin.d',
'http://example.com/is/absolute',
'https://stoplight.io',
'file:///this/is/also/absolute',
'file://c:/and/this/is/../absolute',
])('treats %s path as absolute', filepath => {
expect(isAbsolute(filepath)).toBe(true);
});

it.each(['foo/bar', 'test', ''])('treats %s path as non-absolute', filepath => {
expect(isAbsolute(filepath)).toBe(false);
});
});
76 changes: 76 additions & 0 deletions src/__tests__/join.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { join } from '../';

describe('join', () => {
it('does some basic resolving', () => {
expect(join('/foo/bar', '..', 'baz')).toEqual('/foo/baz');
expect(join('c:/foo/bar', '..', 'baz')).toEqual('c:/foo/baz');
});

it('handles mixed slashes', () => {
expect(join('/test\\baz', 'foo/d')).toEqual('/test/baz/foo/d');
});

it('handles URLs', () => {
expect(join('https://foo.com/pets', '..', 'users', '123')).toEqual('https://foo.com/users/123');
expect(join('https://foo.test', 'com', 'baz')).toEqual('https://foo.test/com/baz');
});

it.each`
args | result
${['.', 'x/b', '..', 'b/c.js']} | ${'x/b/c.js'}
${[]} | ${'.'}
${['/.', 'x/b', '..', 'b/c.js']} | ${'/x/b/c.js'}
${['/foo', '../../../bar']} | ${'/bar'}
${['foo', '../../../bar']} | ${'../../bar'}
${['foo/', '../../../bar']} | ${'../../bar'}
${['foo/x', '../../../bar']} | ${'../bar'}
${['foo/x', './bar']} | ${'foo/x/bar'}
${['foo/x/', './bar']} | ${'foo/x/bar'}
${['foo/x/', '.', 'bar']} | ${'foo/x/bar'}
${['./']} | ${'.'}
${['.', './']} | ${'.'}
${['.', '.', '.']} | ${'.'}
${['.', './', '.']} | ${'.'}
${['.']} | ${'.'}
${['', '.']} | ${'.'}
${['', 'foo']} | ${'foo'}
${['foo', './bar']} | ${'foo/bar'}
${['', '', 'foo']} | ${'foo'}
${['foo', '']} | ${'foo'}
${['foo/', '']} | ${'foo'}
${['foo', '', 'bar']} | ${'foo/bar'}
${['./', '..', 'foo']} | ${'../foo'}
${['./', '..', '..', './foo']} | ${'../../foo'}
${['.', '..', '..', 'foo']} | ${'../../foo'}
${['', '..', '..', 'foo']} | ${'../../foo'}
${['/']} | ${'/'}
${['/', '.']} | ${'/'}
${['/', '..']} | ${'/'}
${['/', '..', '..']} | ${'/'}
${['']} | ${'.'}
${['', '']} | ${'.'}
${[' /foo']} | ${' /foo'}
${[' ', 'foo']} | ${' /foo'}
${[' ', '.']} | ${' '}
${[' ', '']} | ${' '}
${['/', 'foo']} | ${'/foo'}
`('joins $args', ({ args, result }) => {
expect(join(...args)).toBe(result);
});

it.each`
args
${['.', '/./', '.']}
${['.', '/////./', '.']}
${['', '/foo']}
${['', '', '/foo']}
${[' ', '/']}
${['/', '/foo']}
${['/', '//foo']}
${['/', '', '/foo']}
${['', '/', 'foo']}
${['', '/', '/foo']}
`('join($args) to throw', ({ args }) => {
expect(() => join(...args)).toThrow();
});
});
60 changes: 60 additions & 0 deletions src/__tests__/normalize.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { normalize } from '../';

describe('normalize', () => {
describe('replaces Windows-like slashes with POSIX-compatible ones', () => {
it.each`
path | result
${'c:\\foo\\bar'} | ${'c:/foo/bar'}
`("normalize('$path')", ({ path, result }) => {
expect(normalize(path)).toEqual(result);
});
});

describe('ignores POSIX slashes', () => {
it.each`
path | result
${'/d/foo'} | ${'/d/foo'}
`("normalize('$path')", ({ path, result }) => {
expect(normalize(path)).toEqual(result);
});
});

describe('does some basic resolving', () => {
it.each`
path | result
${'/foo/bar/boom/../../baz/.././a'} | ${'/foo/a'}
${'/foo/bar/boom/../a'} | ${'/foo/bar/a'}
${'/foo/bar/boom/..'} | ${'/foo/bar'}
`("normalize('$path')", ({ path, result }) => {
expect(normalize(path)).toEqual(result);
});
});

describe('handles URLs', () => {
it.each`
path | result
${'https://foo.com/baz/bar'} | ${'https://foo.com/baz/bar'}
${'htTps://foo.com/baz/bar'} | ${'https://foo.com/baz/bar'}
${'htTps://foo.com/baz/bar/../foo'} | ${'https://foo.com/baz/foo'}
`("normalize('$path')", ({ path, result }) => {
expect(normalize(path)).toEqual(result);
});
});

describe('resolves .. in absolute paths differently from relative paths', () => {
it.each`
path | result
${'../../foo'} | ${'../../foo'}
${'../../foo/../bar'} | ${'../../bar'}
${'../../foo/../bar/../..'} | ${'../../..'}
${'/../../foo'} | ${'/foo'}
${'/../../foo/../bar'} | ${'/bar'}
${'/../../foo/../bar/../..'} | ${'/'}
${'https://foo.com/../../foo'} | ${'https://foo.com/foo'}
${'https://foo.com/../../foo/../bar'} | ${'https://foo.com/bar'}
${'https://foo.com/../../foo/../bar/../..'} | ${'https://foo.com/'}
`("normalize('$path')", ({ path, result }) => {
expect(normalize(path)).toEqual(result);
});
});
});
74 changes: 74 additions & 0 deletions src/__tests__/relative.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { relative } from '../relative';

describe('relative', () => {
describe('handles POSIX paths', () => {
it.each`
from | to | result
${'/test/bar/a'} | ${'/test/foo/c'} | ${'../../foo/c'}
${'/var/lib'} | ${'/var'} | ${'..'}
${'/var/lib'} | ${'/bin'} | ${'../../bin'}
${'/var/lib'} | ${'/var/lib'} | ${'.'}
${'/var/lib'} | ${'/var/apache'} | ${'../apache'}
${'/var/'} | ${'/var/lib'} | ${'lib'}
${'/'} | ${'/var/lib'} | ${'var/lib'}
${'/foo/test'} | ${'/foo/test/bar/package.json'} | ${'bar/package.json'}
${'/Users/a/web/b/test/mails'} | ${'/Users/a/web/b'} | ${'../..'}
${'/foo/bar/baz-quux'} | ${'/foo/bar/baz'} | ${'../baz'}
${'/foo/bar/baz'} | ${'/foo/bar/baz-quux'} | ${'../baz-quux'}
${'/baz-quux'} | ${'/baz'} | ${'../baz'}
${'/baz'} | ${'/baz-quux'} | ${'../baz-quux'}
`("handles relative('$from', '$to')", ({ from, to, result }) => {
expect(relative(from, to)).toEqual(result);
});
});

describe('handles Windows URIs', () => {
it.each`
from | to | result
${'c:\\test\\baz'} | ${'C:\\test\\foo'} | ${'../foo'}
${'c:/blah\\blah'} | ${'d:/games'} | ${'d:/games'}
${'c:/aaaa/bbbb'} | ${'c:/aaaa'} | ${'..'}
${'c:/aaaa/bbbb'} | ${'c:/cccc'} | ${'../../cccc'}
${'c:/aaaa/bbbb'} | ${'c:/aaaa/bbbb'} | ${'.'}
${'c:/aaaa/bbbb'} | ${'c:/aaaa/cccc'} | ${'../cccc'}
${'c:/aaaa/'} | ${'c:/aaaa/cccc'} | ${'cccc'}
${'c:/'} | ${'c:\\aaaa\\bbbb'} | ${'aaaa/bbbb'}
${'c:/aaaa/bbbb'} | ${'d:\\'} | ${'d:/'}
${'c:/AaAa/bbbb'} | ${'c:/aaaa/bbbb'} | ${'../../aaaa/bbbb'}
${'c:/aaaaa/'} | ${'c:/aaaa/cccc'} | ${'../aaaa/cccc'}
${'C:\\foo\\bar\\baz\\quux'} | ${'C:\\'} | ${'../../../..'}
${'C:\\foo\\test'} | ${'C:\\foo\\test\\bar\\package.json'} | ${'bar/package.json'}
${'C:\\foo\\bar\\baz-quux'} | ${'C:\\foo\\bar\\baz'} | ${'../baz'}
${'C:\\foo\\bar\\baz'} | ${'C:\\foo\\bar\\baz-quux'} | ${'../baz-quux'}
${'\\\\foo\\bar'} | ${'\\\\foo\\bar\\baz'} | ${'baz'}
${'\\\\foo\\bar\\baz'} | ${'\\\\foo\\bar'} | ${'..'}
${'\\\\foo\\bar\\baz-quux'} | ${'\\\\foo\\bar\\baz'} | ${'../baz'}
${'\\\\foo\\bar\\baz'} | ${'\\\\foo\\bar\\baz-quux'} | ${'../baz-quux'}
${'C:\\baz-quux'} | ${'C:\\baz'} | ${'../baz'}
${'C:\\baz'} | ${'C:\\baz-quux'} | ${'../baz-quux'}
${'\\\\foo\\baz-quux'} | ${'\\\\foo\\baz'} | ${'../baz'}
${'\\\\foo\\baz'} | ${'\\\\foo\\baz-quux'} | ${'../baz-quux'}
${'C:\\baz'} | ${'\\\\foo\\bar\\baz'} | ${'/foo/bar/baz'}
${'\\\\foo\\bar\\baz'} | ${'C:\\baz'} | ${'c:/baz'}
`("handles relative('$from', '$to')", ({ from, to, result }) => {
expect(relative(from, to)).toEqual(result);
});
});

it('handles mixed slashes', () => {
expect(relative('/test\\baz', '/test\\foo')).toEqual('../foo');
expect(relative('c:/test\\baz', 'C:/test\\foo')).toEqual('../foo');
});

it('handles URLs', () => {
expect(relative('http://stoplight.io/', 'http://stoplight.io/bar/foo')).toEqual('bar/foo');
expect(relative('http://stoplight.io/bar/z', 'http://stoplight.io/bar/foo/baz')).toEqual('../foo/baz');
});

it('handles different origins', () => {
expect(relative('/a/bar/c', '/x/foo/c')).toEqual('../../../x/foo/c');
expect(relative('https://stop.bar/bar/z/x', 'http://stoplight.io/bar/foo/baz')).toEqual(
'http://stoplight.io/bar/foo/baz',
);
});
});
Loading

0 comments on commit 75c224b

Please sign in to comment.