UNPKG

dpdm

Version:

Analyze circular dependencies in your JavaScript/TypeScript projects.

235 lines 10.5 kB
"use strict"; /*! * Copyright 2019 acrazing <joking.young@gmail.com>. All rights reserved. * @since 2019-07-17 18:45:47 */ Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const fs_extra_1 = tslib_1.__importDefault(require("fs-extra")); const path_1 = require("path"); const utils_1 = require("./utils"); const consts_1 = require("./consts"); describe('util', () => { it('should resolve correctly', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () { const ext = ['', '.js', '.jsx', '.ts', '.tsx', '.json']; const local = yield (0, utils_1.simpleResolver)(__dirname, './bin/dpdm', ext); const index = yield (0, utils_1.simpleResolver)(__dirname, '.', ext); yield fs_extra_1.default.outputJSON('node_modules/dpdm-ut-parent/package.json', { name: 'dpdm-ut-parent', version: '1.0.0', main: 'index.js', dependencies: { 'dpdm-ut-deep': '^1.0.0', }, }); yield fs_extra_1.default.outputFile('node_modules/dpdm-ut-parent/index.js', ''); yield fs_extra_1.default.outputJSON('node_modules/dpdm-ut-parent/node_modules/dpdm-ut-deep/package.json', { name: 'dpdm-ut-deep', version: '1.0.0', main: 'index.js', }); yield fs_extra_1.default.outputFile('node_modules/dpdm-ut-parent/node_modules/dpdm-ut-deep/index.js', ''); yield fs_extra_1.default.outputJSON('node_modules/dpdm-ut-deep/package.json', { name: 'dpdm-ut-deep', version: '2.0.0', main: 'index.js', }); yield fs_extra_1.default.outputFile('node_modules/dpdm-ut-deep/index.js', ''); const pkg = yield (0, utils_1.simpleResolver)(__dirname, 'dpdm-ut-parent', ext); const deepPkg = yield (0, utils_1.simpleResolver)((0, path_1.dirname)(pkg), 'dpdm-ut-deep', ext); const notFound = yield (0, utils_1.simpleResolver)(__dirname, './utils.tsx', ext); expect([local, index, pkg, deepPkg, notFound]).toEqual([ (0, path_1.join)(__dirname, 'bin/dpdm.ts'), (0, path_1.join)(__dirname, 'index.ts'), (0, path_1.join)(__dirname, '../node_modules/dpdm-ut-parent/index.js'), (0, path_1.join)(__dirname, '../node_modules/dpdm-ut-parent/node_modules/dpdm-ut-deep/index.js'), null, ]); })); describe('When parsing circular', () => { function dependencyFactory(id, issuer = '', kind = consts_1.DependencyKind.StaticImport) { return { issuer, request: '', kind, id, }; } describe('When tree is empty', () => { const tree = {}; it('Should return empty array', () => { const actual = (0, utils_1.parseCircular)(tree); expect(actual.length).toBe(0); }); }); describe('When tree has just a root with no dependencies', () => { const tree = { a: [] }; it('Should return empty array', () => { const actual = (0, utils_1.parseCircular)(tree); expect(actual.length).toBe(0); }); }); describe('When tree has 2 nodes, no cycle', () => { const tree = { a: [dependencyFactory('b')], b: [] }; it('Should return empty array', () => { const actual = (0, utils_1.parseCircular)(tree); expect(actual.length).toBe(0); }); }); describe('When tree has 2 nodes, with cycle', () => { const id1 = 'a'; const id2 = 'b'; const tree = { [id1]: [dependencyFactory(id2)], [id2]: [dependencyFactory(id1)], }; let actual; beforeAll(() => { actual = (0, utils_1.parseCircular)(tree); }); it('Should return non-empty array', () => { expect(actual.length).toBeGreaterThan(0); }); it('Should count only one cycle', () => { expect(actual.length).toBe(1); }); it('Should include the ids involved in the cycle', () => { expect(actual[0]).toMatchObject([id1, id2]); }); }); describe('When tree has a deep cycle', () => { const ids = ['a', 'b', 'c']; const tree = { [ids[0]]: [dependencyFactory(ids[1])], [ids[1]]: [dependencyFactory(ids[2])], [ids[2]]: [dependencyFactory(ids[0])], }; let actual; beforeAll(() => { actual = (0, utils_1.parseCircular)(tree); }); it('Should return non-empty array', () => { expect(actual.length).toBeGreaterThan(0); }); it('Should count only one cycle', () => { expect(actual.length).toBe(1); }); it('Should include the ids involved in the cycle', () => { expect(actual[0]).toMatchObject(ids); }); }); describe('When tree has 2 cycles with no intersection', () => { const tree = { left1: [dependencyFactory('left2')], left2: [dependencyFactory('left1')], right1: [dependencyFactory('right2')], right2: [dependencyFactory('right1')], }; let actual; beforeAll(() => { actual = (0, utils_1.parseCircular)(tree); }); it('Should return non-empty array', () => { expect(actual.length).toBeGreaterThan(0); }); it('Should count two cycles', () => { expect(actual.length).toBe(2); }); it('Should include the ids involved in the cycle', () => { expect(actual[0]).toMatchObject(['left1', 'left2']); expect(actual[1]).toMatchObject(['right1', 'right2']); }); }); describe('When tree has 2 cycles from common node', () => { const tree = { start: [dependencyFactory('left'), dependencyFactory('right')], left: [dependencyFactory('start')], right: [dependencyFactory('start')], }; let actual; beforeAll(() => { actual = (0, utils_1.parseCircular)(tree); }); it('Should return non-empty array', () => { expect(actual.length).toBeGreaterThan(0); }); it('Should count two cycles', () => { expect(actual.length).toBe(2); }); it('Should include the ids involved in the cycle', () => { expect(actual[0]).toMatchObject(['start', 'left']); expect(actual[1]).toMatchObject(['start', 'right']); }); }); describe('When tree has 2 cycles with multi-node intersection', () => { const tree = { start: [dependencyFactory('mid')], mid: [dependencyFactory('left'), dependencyFactory('right')], left: [dependencyFactory('start')], right: [dependencyFactory('start')], }; let actual; beforeAll(() => { actual = (0, utils_1.parseCircular)(tree); }); it('Should return non-empty array', () => { expect(actual.length).toBeGreaterThan(0); }); it('Should count two cycles', () => { expect(actual.length).toBe(2); }); it('Should include the ids involved in the cycle', () => { expect(actual[0]).toMatchObject(['start', 'mid', 'left']); expect(actual[1]).toMatchObject(['start', 'mid', 'right']); }); }); describe('When skip imports are specified', () => { it('Should not skip imports when the skip list is empty', () => { const tree = { a: [dependencyFactory('b', 'a')], b: [dependencyFactory('a', 'b')], }; expect((0, utils_1.parseCircular)(tree, false, [])).toEqual([['a', 'b']]); }); it('Should ignore a matching import edge when parsing circulars', () => { const tree = { a: [dependencyFactory('b', 'a')], b: [dependencyFactory('a', 'b')], }; expect((0, utils_1.parseCircular)(tree, false, [['b', 'a']])).toEqual([]); }); it('Should only ignore the specified import edge', () => { const tree = { start: [ dependencyFactory('left', 'start'), dependencyFactory('right', 'start'), ], left: [dependencyFactory('start', 'left')], right: [dependencyFactory('start', 'right')], }; const actual = (0, utils_1.parseCircular)(tree, false, [['left', 'start']]); expect(actual).toHaveLength(1); expect(actual[0]).toMatchObject(['start', 'right']); }); it('Should support regexp patterns for skipped imports', () => { const tree = { 'src/a.js': [ dependencyFactory('src/b.js', 'src/a.js'), dependencyFactory('src/c.js', 'src/a.js'), ], 'src/b.js': [dependencyFactory('src/a.js', 'src/b.js')], 'src/c.js': [dependencyFactory('src/a.js', 'src/c.js')], }; expect((0, utils_1.parseCircular)(tree, false, [['src/a.js', '.*']])).toEqual([]); }); it('Should not match skipped imports by prefix', () => { const tree = { a: [dependencyFactory('bc', 'a')], bc: [dependencyFactory('a', 'bc')], }; expect((0, utils_1.parseCircular)(tree, false, [['a', 'b']])).toEqual([['a', 'bc']]); }); }); }); }); //# sourceMappingURL=utils.spec.js.map