diff --git a/src/build-app-output/build-depcache-output.js b/src/build-depcache-output/index.js similarity index 70% rename from src/build-app-output/build-depcache-output.js rename to src/build-depcache-output/index.js index 55e9ecd..141d67e 100644 --- a/src/build-app-output/build-depcache-output.js +++ b/src/build-depcache-output/index.js @@ -1,17 +1,17 @@ import ac from 'argument-contracts'; -import { checkForRequiredInitialization } from './check-for-required-initialization'; +import { checkForRequiredInitialization } from '../build-app-output/check-for-required-initialization'; import { CliOptions, DO_NOT_INJECT } from '../cli-options'; import fs from 'fs'; -import { getDependencyPackages } from './get-dependency-packages'; +import { getDependencyPackages } from '../build-app-output/get-dependency-packages'; import { Logger } from '../logger'; import path from 'path'; -import { readPackageDependencies } from './read-package-dependencies'; -import { rollupLatestMajorVersions } from './rollup-latest-major-versions'; -import { throwForConflictingMajorVersions } from './throw-for-conflicting-major-versions'; -import { throwIfZerothLevelDepNotHighestMajorVersion } from './throw-if-zeroth-level-dep-not-highest-major-version'; -import { buildDependencyArray } from './build-dependency-array'; -import { pareDownToKnownPackages } from './pare-down-to-known-packages'; -import { adjustOrderBasedOnChildDependencies } from './adjust-order-based-on-child-dependencies'; +import { readPackageDependencies } from '../build-app-output/read-package-dependencies'; +import { rollupLatestMajorVersions } from '../build-app-output/rollup-latest-major-versions'; +import { throwForConflictingMajorVersions } from '../build-app-output/throw-for-conflicting-major-versions'; +import { throwIfZerothLevelDepNotHighestMajorVersion } from '../build-app-output/throw-if-zeroth-level-dep-not-highest-major-version'; +import { buildDependencyArray } from '../build-app-output/build-dependency-array'; +import { pareDownToKnownPackages } from '../build-app-output/pare-down-to-known-packages'; +import { adjustOrderBasedOnChildDependencies } from '../build-app-output/adjust-order-based-on-child-dependencies'; import { resolveRequiredDependencyScripts } from './resolve-required-dependency-scripts'; const currentWorkingDirectory = process.cwd(); @@ -20,7 +20,7 @@ export async function buildDepcacheOutput(cliOptions) { ac.assertType(cliOptions, CliOptions, 'cliOptions'); Logger.setLoggingLevel(cliOptions.logging); - Logger.debug(`buildAppOutput: cliOptions: ${JSON.stringify(cliOptions)}`); + Logger.debug(`buildDepcacheOutput: cliOptions: ${JSON.stringify(cliOptions)}`); const dependencies = readPackageDependencies(path.join(currentWorkingDirectory, cliOptions.pathToPackageJson)); Logger.debug('dependencies', JSON.stringify(dependencies, null, 2)); @@ -59,7 +59,7 @@ export async function buildDepcacheOutput(cliOptions) { }); const output = [ - ...dependencyScripts.map(script => script.replace(/"/g, '')) + ...dependencyScripts ]; if (cliOptions.injectFile && cliOptions.injectFile !== DO_NOT_INJECT) { diff --git a/src/build-depcache-output/index.spec.js b/src/build-depcache-output/index.spec.js new file mode 100644 index 0000000..a1de7d8 --- /dev/null +++ b/src/build-depcache-output/index.spec.js @@ -0,0 +1,213 @@ +import ac from 'argument-contracts'; +import * as AdjustOrderBasedOnChildDependenciesModule from '../build-app-output/adjust-order-based-on-child-dependencies'; +import * as CheckForRequiredInitializationModule from '../build-app-output/check-for-required-initialization'; +import { CliOptions } from '../cli-options'; +import fs from 'fs'; +import * as BuildDependencyArrayModule from '../build-app-output/build-dependency-array'; +import * as GetDependencyPackagesModule from '../build-app-output/get-dependency-packages'; +import { Logger } from '../logger'; +import * as PareDownToKnownPackagesModule from '../build-app-output/pare-down-to-known-packages'; +import path from 'path'; +import * as ReadPackageDependenciesModule from '../build-app-output/read-package-dependencies'; +import * as ResolveRequiredDependencyScriptsModule from './resolve-required-dependency-scripts'; +import * as RollupLatestMajorVersionsModule from '../build-app-output/rollup-latest-major-versions'; +import * as ThrowForConflictingMajorVersionsModule from '../build-app-output/throw-for-conflicting-major-versions'; +import * as ThrowIfZerothLevelDepNotHighestMajorVersionModule from '../build-app-output/throw-if-zeroth-level-dep-not-highest-major-version'; + +import { buildDepcacheOutput } from './index'; + +describe('build depcache output', () => { + let cliOptions; + + beforeEach(() => { + + spyOn(ac, 'assertType'); + spyOn(AdjustOrderBasedOnChildDependenciesModule, 'adjustOrderBasedOnChildDependencies').and.returnValue([]); + spyOn(CheckForRequiredInitializationModule, 'checkForRequiredInitialization'); + spyOn(fs, 'writeFileSync'); + spyOn(BuildDependencyArrayModule, 'buildDependencyArray').and.resolveTo([]); + spyOn(GetDependencyPackagesModule, 'getDependencyPackages').and.resolveTo([]); + spyOn(Logger, 'setLoggingLevel'); + spyOn(PareDownToKnownPackagesModule, 'pareDownToKnownPackages').and.returnValue([]); + spyOn(ReadPackageDependenciesModule, 'readPackageDependencies'); + spyOn(ResolveRequiredDependencyScriptsModule, 'resolveRequiredDependencyScripts').and.returnValue([]); + spyOn(RollupLatestMajorVersionsModule, 'rollupLatestMajorVersions').and.returnValue([]); + spyOn(ThrowForConflictingMajorVersionsModule, 'throwForConflictingMajorVersions'); + spyOn(ThrowIfZerothLevelDepNotHighestMajorVersionModule, 'throwIfZerothLevelDepNotHighestMajorVersion'); + spyOn(Logger, 'debug'); + + cliOptions = new CliOptions({ + excludeDirectDependencies: false, + dependencyDirectory: 'her/there/everywhere', + openFileLimit: 4, + orchardInjectString: '', + outputFile: 'plumbus.html', + retryOpenFileSleepDuration: 10, + outputDepcache: true + }); + }); + + it('should assert cliOptions is CliOptions', async () => { + await buildDepcacheOutput(cliOptions); + + expect(ac.assertType).toHaveBeenCalledWith(cliOptions, CliOptions, 'cliOptions'); + }); + + it('should set logging level from cliOptions', async () => { + const logging = 'complete deforestation'; + await buildDepcacheOutput({ + ...cliOptions, + logging + }); + + expect(Logger.setLoggingLevel).toHaveBeenCalledWith(logging); + }); + + it('should read package.json dependencies from cliOptions', async () => { + const pathToPackageJson = 'go/here/for/package.json'; + await buildDepcacheOutput({ + ...cliOptions, + pathToPackageJson + }); + + expect(ReadPackageDependenciesModule.readPackageDependencies).toHaveBeenCalledWith(path.join(process.cwd(), pathToPackageJson)); + }); + + it('should get array of dependencies', async () => { + const openFileLimit = 'twenty'; + const retryOpenFileSleepDuration = '1 siesta'; + + await buildDepcacheOutput({ + ...cliOptions, + openFileLimit, + retryOpenFileSleepDuration + }); + + expect(BuildDependencyArrayModule.buildDependencyArray).toHaveBeenCalledWith(jasmine.objectContaining({ + currentWorkingDirectory: jasmine.any(String), + pathToPackageJson: cliOptions.pathToPackageJson + })); + }); + + it('should rollup major versions', async () => { + const packageDependencies = [1, 2, 3]; + PareDownToKnownPackagesModule.pareDownToKnownPackages.and.returnValue(packageDependencies); + + await buildDepcacheOutput(cliOptions); + + expect(RollupLatestMajorVersionsModule.rollupLatestMajorVersions).toHaveBeenCalledWith(packageDependencies); + }); + + it('should check for package major version conflicts', async () => { + const dependencyMap = { yes: 'maybe..... no' }; + const packageDependencies = [1, 2, 3]; + GetDependencyPackagesModule.getDependencyPackages.and.resolveTo(dependencyMap); + RollupLatestMajorVersionsModule.rollupLatestMajorVersions.and.returnValue(packageDependencies); + + await buildDepcacheOutput(cliOptions); + + expect(ThrowForConflictingMajorVersionsModule.throwForConflictingMajorVersions).toHaveBeenCalledWith({ + dependencies: packageDependencies, + dependencyMap + }); + }); + + it('should check for required initializations', async () => { + const dependencyMap = { yes: 'maybe..... no' }; + const packageDependencies = [3, 2, 1]; + GetDependencyPackagesModule.getDependencyPackages.and.resolveTo(dependencyMap); + RollupLatestMajorVersionsModule.rollupLatestMajorVersions.and.returnValue(packageDependencies); + + await buildDepcacheOutput(cliOptions); + + expect(CheckForRequiredInitializationModule.checkForRequiredInitialization).toHaveBeenCalledWith({ dependencies: packageDependencies, dependencyMap }); + }); + + it('should checkout for package 0 level dependency not major version issues', async () => { + const dependencyMap = { yes: 'maybe..... no' }; + const packageDependencies = [1, 2, 3]; + GetDependencyPackagesModule.getDependencyPackages.and.resolveTo(dependencyMap); + RollupLatestMajorVersionsModule.rollupLatestMajorVersions.and.returnValue(packageDependencies); + + await buildDepcacheOutput(cliOptions); + + expect(ThrowIfZerothLevelDepNotHighestMajorVersionModule.throwIfZerothLevelDepNotHighestMajorVersion).toHaveBeenCalledWith(packageDependencies); + }); + + it('should resolve dependency scripts', async () => { + const dependencyMap = { all: 'The things!' }; + GetDependencyPackagesModule.getDependencyPackages.and.resolveTo(dependencyMap); + + await buildDepcacheOutput(cliOptions); + + expect(ResolveRequiredDependencyScriptsModule.resolveRequiredDependencyScripts).toHaveBeenCalledWith(jasmine.objectContaining({ + dependencyMap: jasmine.objectContaining(dependencyMap) + })); + }); + + it('should resolve dependency tree', async () => { + const packageDependencies = [1, 2, 3]; + AdjustOrderBasedOnChildDependenciesModule.adjustOrderBasedOnChildDependencies.and.returnValue(packageDependencies); + + await buildDepcacheOutput(cliOptions); + + expect(ResolveRequiredDependencyScriptsModule.resolveRequiredDependencyScripts).toHaveBeenCalledWith(jasmine.objectContaining({ + dependencies: packageDependencies + })); + }); + + describe('injection handling', () => { + beforeEach(() => { + spyOn(fs, 'readFileSync'); + }); + + it('should read file to inject to', async () => { + const injectFile = 'inject/file/location.txt'; + fs.readFileSync.and.returnValue(''); + + await buildDepcacheOutput({ + ...cliOptions, + injectFile + }); + + expect(fs.readFileSync).toHaveBeenCalledWith(injectFile, { encoding: 'utf8' }); + }); + + it('should inject output into the file', async () => { + const orchardInjectString = 'watwatwatwatwat'; + const outputFile = 'The best output'; + const beforeInjectionLocation = 'This file has been injected into!'; + const afterInjectionLocation = 'YEAH BOIIIIIIIIIII!'; + const fileContent = `${beforeInjectionLocation}${orchardInjectString}${afterInjectionLocation}`; + const output = 'The greatest output Evar'; + fs.readFileSync.and.returnValue(fileContent); + ResolveRequiredDependencyScriptsModule.resolveRequiredDependencyScripts.and.returnValue([output]) + + await buildDepcacheOutput({ + ...cliOptions, + injectFile: 'yarp.txt', + orchardInjectString, + outputFile + }); + + + expect(fs.writeFileSync).toHaveBeenCalledWith(outputFile, jasmine.stringMatching(beforeInjectionLocation)); + expect(fs.writeFileSync).toHaveBeenCalledWith(outputFile, jasmine.stringMatching(output)); + expect(fs.writeFileSync).toHaveBeenCalledWith(outputFile, jasmine.stringMatching(afterInjectionLocation)); + }); + }); + + it('should output tags array', async () => { + const outputFile = 'The best output'; + + const dependencyOutput = 'AW YEAH!'; + ResolveRequiredDependencyScriptsModule.resolveRequiredDependencyScripts.and.returnValue([dependencyOutput]) + + await buildDepcacheOutput({ + ...cliOptions, + outputFile + }); + + expect(fs.writeFileSync).toHaveBeenCalledWith(outputFile, jasmine.stringMatching(dependencyOutput)); + }); +}); diff --git a/src/build-app-output/resolve-required-dependency-scripts/index.js b/src/build-depcache-output/resolve-required-dependency-scripts/index.js similarity index 95% rename from src/build-app-output/resolve-required-dependency-scripts/index.js rename to src/build-depcache-output/resolve-required-dependency-scripts/index.js index d8351b3..72ce4f9 100644 --- a/src/build-app-output/resolve-required-dependency-scripts/index.js +++ b/src/build-depcache-output/resolve-required-dependency-scripts/index.js @@ -27,5 +27,5 @@ export function resolveRequiredDependencyScripts({ dependencies, dependencyMap } return scriptsArray; }, []); - return scriptsArray.map(script => `"${script}"`); + return scriptsArray; } \ No newline at end of file diff --git a/src/build-depcache-output/resolve-required-dependency-scripts/index.spec.js b/src/build-depcache-output/resolve-required-dependency-scripts/index.spec.js new file mode 100644 index 0000000..38c308f --- /dev/null +++ b/src/build-depcache-output/resolve-required-dependency-scripts/index.spec.js @@ -0,0 +1,53 @@ +import ac from 'argument-contracts'; +import { resolveRequiredDependencyScripts } from './index'; + +describe('resolve required dependency scripts', () => { + beforeEach(() => { + spyOn(ac, 'assertType'); + }); + + it('should assert dependencies is an object', () => { + const dependencies = []; + + resolveRequiredDependencyScripts({ dependencies, dependencyMap: {} }); + + expect(ac.assertType).toHaveBeenCalledWith(dependencies, Object, 'dependencies'); + }); + + it('should assert dependencyMap is an object', () => { + const dependencyMap = { yes: 'but no' }; + + resolveRequiredDependencyScripts({ dependencies: [], dependencyMap }); + + expect(ac.assertType).toHaveBeenCalledWith(dependencyMap, Object, 'dependencyMap'); + }); + + it('should return an array of scripts', () => { + const dependencyNameOne = '@meltwater/the-big-bad-dependency-dude'; + const dependencyNameTwo = '@meltwater/way-to-dependency-man'; + const notInDepsDependencyName = '@meltwater/no-deps-on-me'; + + const dependencies = [ + { + packageName: dependencyNameOne, + version: '2.3.2', + }, + { + packageName: dependencyNameTwo, + version: '0.0.1' + } + ]; + const dependencyMap = { + [dependencyNameOne]: { dep: 'yup', getEsmUrls: () => ['yup'] }, + [dependencyNameTwo]: { dep: 'yarp', getEsmUrls: () => ['yarp'] }, + [notInDepsDependencyName]: { notDep: 'nope', getEsmUrls: () => ['nope'] } + }; + + const result = resolveRequiredDependencyScripts({ dependencies, dependencyMap }); + + expect(result).toEqual(jasmine.arrayContaining([ + dependencyMap[dependencyNameOne].dep, + dependencyMap[dependencyNameTwo].dep, + ])) + }); +}); diff --git a/src/cli/index.js b/src/cli/index.js index db6379b..1064c22 100644 --- a/src/cli/index.js +++ b/src/cli/index.js @@ -2,7 +2,7 @@ import sywac from 'sywac'; import { ORCHARD_INJECT_STRING } from '../constants'; import { CliOptions } from '../cli-options'; import { buildAppOutput } from '../build-app-output'; -import { buildDepcacheOutput } from '../build-app-output/build-depcache-output.js'; +import { buildDepcacheOutput } from '../build-depcache-output'; import { Logger, LOGGING_LEVEL } from '../logger'; Logger.setLoggingLevel(LOGGING_LEVEL.DEBUG); diff --git a/src/main.js b/src/main.js index 5fbf17b..fe31b8e 100644 --- a/src/main.js +++ b/src/main.js @@ -4,4 +4,4 @@ export { DO_NOT_INJECT } from './cli-options'; export { buildAppOutput } from './build-app-output'; -export { buildDepcacheOutput } from './build-app-output/build-depcache-output.js'; +export { buildDepcacheOutput } from './build-depcache-output';