Skip to content
This repository has been archived by the owner on Jul 4, 2023. It is now read-only.

Commit

Permalink
fix(serve): fix project reference related crash
Browse files Browse the repository at this point in the history
Create a temporary program whenever the solution build does not produce one

fix #401
  • Loading branch information
tamj0rd2 committed Aug 27, 2020
1 parent 0c23e53 commit 71f949e
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 67 deletions.
41 changes: 0 additions & 41 deletions src/schema/watching-schema-generator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,47 +52,6 @@ describe('watching schema generator', () => {

expect(stubSolution.build).toBeCalledTimes(1)
})

describe('given some typescript outputs are not cached', () => {
it('does not create a temporary program', async () => {
stubSolution.getNextInvalidatedProject.mockReturnValue(expect.anything())

await initialiseGenerator()

expect(stubTsHelpers.createProgram).not.toBeCalled()
})

it('starts watching the solution for changes', async () => {
stubSolution.getNextInvalidatedProject.mockReturnValue(expect.anything())

await initialiseGenerator()

expect(stubSolution.build).toBeCalledWith(resolvedTsconfigPath)
})
})

describe('given all typescript outputs are already cached', () => {
it('creates a temporary program', async () => {
await initialiseGenerator()

expect(stubTsHelpers.createProgram).toBeCalledWith(resolvedTsconfigPath, { shouldTypecheck: true })
})

it('throws when a temporary program could not be created', async () => {
const expectedError = new Error('welp')
stubTsHelpers.createProgram.mockImplementation(() => {
throw expectedError
})

await expect(initialiseGenerator()).rejects.toThrowError(expectedError)
})

it('starts watching the solution for changes', async () => {
await initialiseGenerator()

expect(stubSolution.build).toBeCalledWith(resolvedTsconfigPath)
})
})
})

describe('load', () => {
Expand Down
47 changes: 21 additions & 26 deletions src/schema/watching-schema-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,54 +69,49 @@ export class WatchingSchemaGenerator implements SchemaRetriever {
const wasCompilationSuccessful =
diagnostics.filter((d) => d.category === ts.DiagnosticCategory.Error).length === 0

const thereAreMoreProjectsToBuild =
watcherProgram.getCompilerOptions().configFilePath !== this.tsconfigPath ||
!!solution.getNextInvalidatedProject()

if (!this.state.hasCompiledSuccessfullyAtLeastOnce) {
const failureShouldBeHandledByBuildExitCode = !wasCompilationSuccessful
if (failureShouldBeHandledByBuildExitCode) return
if (thereAreMoreProjectsToBuild) return

const thereAreMoreProjectsToCompile = !!solution.getNextInvalidatedProject()
if (thereAreMoreProjectsToCompile) return

this.logger.verbose('able to get a program via the solution watcher')
this.state.hasCompiledSuccessfullyAtLeastOnce = true
this.setInternalSchemaGenerator(watcherProgram.getProgram())
initMetric.success()
return
}

if (wasCompilationSuccessful) {
const mainProjectProgram = this.tsHelpers.createProgram(this.tsconfigPath, {
shouldTypecheck: false,
skipBuildingSolution: true,
})
this.setInternalSchemaGenerator(mainProjectProgram)
if (thereAreMoreProjectsToBuild) return
this.setInternalSchemaGenerator(watcherProgram.getProgram())
this.watchSubscriptions.onSuccess.forEach((hook) => hook())
} else {
this.watchSubscriptions.onFailure.forEach((hook) => hook())
}
}

// the above function does not get executed unless there are invalidated projects,
// so instead we build a temporary program using a different strategy
const shouldBuildTemporaryProgram = !solution.getNextInvalidatedProject()
if (shouldBuildTemporaryProgram) {
this.logger.verbose('no invalidated projects - going to build a temporary program')
try {
const tempProgram = this.tsHelpers.createProgram(this.tsconfigPath, { shouldTypecheck: true })
this.setInternalSchemaGenerator(tempProgram)
this.state.hasCompiledSuccessfullyAtLeastOnce = true
} catch (err) {
initMetric.fail()
return reject(err)
}
}

// this is what watches the solution and kicks of the initial build (if there are invalidated projects)
const solutionBuildResult = solution.build(this.tsconfigPath)
const solutionBuildResult = solution.build()
if (solutionBuildResult !== ts.ExitStatus.Success) {
initMetric.fail()
return reject(new Error('Could not compile your typescript source files'))
}

resolve()
if (this.schemaGenerator) return resolve()

this.logger.verbose('main project has not been invalidated - going to build a temporary program')
try {
const tempProgram = this.tsHelpers.createProgram(this.tsconfigPath, { shouldTypecheck: true })
this.setInternalSchemaGenerator(tempProgram)
this.state.hasCompiledSuccessfullyAtLeastOnce = true
return resolve()
} catch (err) {
initMetric.fail()
return reject(err)
}
})
}

Expand Down

0 comments on commit 71f949e

Please sign in to comment.