on-zero 0.16.20 → 0.16.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/cli.cjs +6 -0
- package/dist/cjs/cli.native.js +6 -0
- package/dist/cjs/cli.native.js.map +1 -1
- package/dist/cjs/combineZeroClients.native.js.map +1 -1
- package/dist/cjs/config.native.js.map +1 -1
- package/dist/cjs/createPermissions.native.js.map +1 -1
- package/dist/cjs/createSchemaFromDrizzle.native.js.map +1 -1
- package/dist/cjs/createUseQuery.cjs +14 -4
- package/dist/cjs/createUseQuery.native.js +18 -5
- package/dist/cjs/createUseQuery.native.js.map +1 -1
- package/dist/cjs/createUseQueryDirect.cjs +13 -2
- package/dist/cjs/createUseQueryDirect.native.js +14 -2
- package/dist/cjs/createUseQueryDirect.native.js.map +1 -1
- package/dist/cjs/createZeroClient.authData.test.native.js.map +1 -1
- package/dist/cjs/createZeroClient.cjs +21 -3
- package/dist/cjs/createZeroClient.connection.test.native.js.map +1 -1
- package/dist/cjs/createZeroClient.exportProbe.test.native.js.map +1 -1
- package/dist/cjs/createZeroClient.headless.test.native.js.map +1 -1
- package/dist/cjs/createZeroClient.httpAuth.test.native.js.map +1 -1
- package/dist/cjs/createZeroClient.native.js +28 -3
- package/dist/cjs/createZeroClient.native.js.map +1 -1
- package/dist/cjs/createZeroClient.recovery.test.native.js.map +1 -1
- package/dist/cjs/generate-helpers.native.js.map +1 -1
- package/dist/cjs/generate-helpers.test.native.js.map +1 -1
- package/dist/cjs/generate-layout.native.js.map +1 -1
- package/dist/cjs/generate-lite.native.js.map +1 -1
- package/dist/cjs/generate-lite.test.native.js.map +1 -1
- package/dist/cjs/generate.cjs +57 -30
- package/dist/cjs/generate.native.js +92 -31
- package/dist/cjs/generate.native.js.map +1 -1
- package/dist/cjs/generate.test.cjs +147 -0
- package/dist/cjs/generate.test.native.js +147 -0
- package/dist/cjs/generate.test.native.js.map +1 -1
- package/dist/cjs/helpers/NullToOptional.native.js.map +1 -1
- package/dist/cjs/helpers/asyncContext.hostStorage.test.native.js.map +1 -1
- package/dist/cjs/helpers/batchQuery.native.js.map +1 -1
- package/dist/cjs/helpers/clearZeroClientData.native.js.map +1 -1
- package/dist/cjs/helpers/createMutators.native.js.map +1 -1
- package/dist/cjs/helpers/createMutators.test.native.js.map +1 -1
- package/dist/cjs/helpers/ellipsis.native.js.map +1 -1
- package/dist/cjs/helpers/emitter.native.js.map +1 -1
- package/dist/cjs/helpers/ensure.native.js.map +1 -1
- package/dist/cjs/helpers/ensureLoggedIn.native.js.map +1 -1
- package/dist/cjs/helpers/errors.native.js.map +1 -1
- package/dist/cjs/helpers/getAuth.native.js.map +1 -1
- package/dist/cjs/helpers/getCurrentComponentStack.native.js.map +1 -1
- package/dist/cjs/helpers/globalValue.native.js.map +1 -1
- package/dist/cjs/helpers/hostStorageScope.native.js.map +1 -1
- package/dist/cjs/helpers/mapObject.native.js.map +1 -1
- package/dist/cjs/helpers/mutationLifecycle.native.js.map +1 -1
- package/dist/cjs/helpers/mutationLifecycle.test.native.js.map +1 -1
- package/dist/cjs/helpers/mutatorContext.native.js.map +1 -1
- package/dist/cjs/helpers/mutatorContext.test.native.js.map +1 -1
- package/dist/cjs/helpers/prettyFormatZeroQuery.native.js.map +1 -1
- package/dist/cjs/helpers/queryContext.native.js.map +1 -1
- package/dist/cjs/helpers/recoverZeroClient.native.js.map +1 -1
- package/dist/cjs/helpers/recoverZeroClient.test.native.js.map +1 -1
- package/dist/cjs/helpers/showZeroClientError.native.js.map +1 -1
- package/dist/cjs/helpers/sleep.native.js.map +1 -1
- package/dist/cjs/helpers/time.native.js.map +1 -1
- package/dist/cjs/helpers/tuple.native.js.map +1 -1
- package/dist/cjs/helpers/useMutation.native.js.map +1 -1
- package/dist/cjs/helpers/useMutation.test.native.js.map +1 -1
- package/dist/cjs/helpers/useZeroDebug.native.js.map +1 -1
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/instanceRegistry.native.js.map +1 -1
- package/dist/cjs/modelRegistry.native.js.map +1 -1
- package/dist/cjs/multi.cjs +10 -5
- package/dist/cjs/multi.native.js +10 -5
- package/dist/cjs/multi.native.js.map +1 -1
- package/dist/cjs/multiInstance.test.native.js.map +1 -1
- package/dist/cjs/multiInstanceMutations.test.native.js.map +1 -1
- package/dist/cjs/multiInstanceNested.test.native.js.map +1 -1
- package/dist/cjs/multiPartition.test.cjs +46 -2
- package/dist/cjs/multiPartition.test.native.js +50 -2
- package/dist/cjs/multiPartition.test.native.js.map +1 -1
- package/dist/cjs/mutations.native.js.map +1 -1
- package/dist/cjs/mutations.test.native.js.map +1 -1
- package/dist/cjs/native-typescript.cjs +50 -11
- package/dist/cjs/native-typescript.native.js +158 -30
- package/dist/cjs/native-typescript.native.js.map +1 -1
- package/dist/cjs/provideZero.eagerInstance.test.cjs +22 -0
- package/dist/cjs/provideZero.eagerInstance.test.native.js +30 -0
- package/dist/cjs/provideZero.eagerInstance.test.native.js.map +1 -1
- package/dist/cjs/provideZero.hydration.test.native.js.map +1 -1
- package/dist/cjs/provideZero.ssr.test.native.js.map +1 -1
- package/dist/cjs/queryErrorRecovery.cjs +93 -0
- package/dist/cjs/queryErrorRecovery.native.js +205 -0
- package/dist/cjs/queryErrorRecovery.native.js.map +1 -0
- package/dist/cjs/queryJson.native.js.map +1 -1
- package/dist/cjs/queryRegistry.native.js.map +1 -1
- package/dist/cjs/resolveQuery.native.js.map +1 -1
- package/dist/cjs/run.native.js.map +1 -1
- package/dist/cjs/server.native.js.map +1 -1
- package/dist/cjs/server.test.native.js.map +1 -1
- package/dist/cjs/serverWhere.native.js.map +1 -1
- package/dist/cjs/serverWhere.test.native.js.map +1 -1
- package/dist/cjs/state.native.js.map +1 -1
- package/dist/cjs/streaming.native.js.map +1 -1
- package/dist/cjs/testSetup.native.js.map +1 -1
- package/dist/cjs/types.native.js.map +1 -1
- package/dist/cjs/usePermission.test.native.js.map +1 -1
- package/dist/cjs/useQuery.aggregate.zero.test.cjs +199 -4
- package/dist/cjs/useQuery.aggregate.zero.test.native.js +212 -4
- package/dist/cjs/useQuery.aggregate.zero.test.native.js.map +1 -1
- package/dist/cjs/useQuery.empty.test.native.js.map +1 -1
- package/dist/cjs/useQuery.ssr.test.native.js.map +1 -1
- package/dist/cjs/useStreamingField.loop.test.native.js.map +1 -1
- package/dist/cjs/useStreamingField.native.js.map +1 -1
- package/dist/cjs/vite-plugin.cjs +10 -0
- package/dist/cjs/vite-plugin.native.js +10 -0
- package/dist/cjs/vite-plugin.native.js.map +1 -1
- package/dist/cjs/where.native.js.map +1 -1
- package/dist/cjs/zeroRunner.native.js.map +1 -1
- package/dist/cjs/zql.native.js.map +1 -1
- package/dist/esm/cli.mjs +6 -0
- package/dist/esm/cli.mjs.map +1 -1
- package/dist/esm/cli.native.js +7 -1
- package/dist/esm/cli.native.js.map +1 -1
- package/dist/esm/combineZeroClients.native.js +4 -4
- package/dist/esm/combineZeroClients.native.js.map +1 -1
- package/dist/esm/config.native.js.map +1 -1
- package/dist/esm/createPermissions.native.js +4 -4
- package/dist/esm/createPermissions.native.js.map +1 -1
- package/dist/esm/createSchemaFromDrizzle.native.js +1 -1
- package/dist/esm/createSchemaFromDrizzle.native.js.map +1 -1
- package/dist/esm/createUseQuery.mjs +16 -6
- package/dist/esm/createUseQuery.mjs.map +1 -1
- package/dist/esm/createUseQuery.native.js +24 -11
- package/dist/esm/createUseQuery.native.js.map +1 -1
- package/dist/esm/createUseQueryDirect.mjs +13 -2
- package/dist/esm/createUseQueryDirect.mjs.map +1 -1
- package/dist/esm/createUseQueryDirect.native.js +19 -7
- package/dist/esm/createUseQueryDirect.native.js.map +1 -1
- package/dist/esm/createZeroClient.authData.test.native.js +2 -2
- package/dist/esm/createZeroClient.authData.test.native.js.map +1 -1
- package/dist/esm/createZeroClient.connection.test.native.js +1 -1
- package/dist/esm/createZeroClient.connection.test.native.js.map +1 -1
- package/dist/esm/createZeroClient.exportProbe.test.native.js +1 -1
- package/dist/esm/createZeroClient.exportProbe.test.native.js.map +1 -1
- package/dist/esm/createZeroClient.headless.test.native.js +2 -2
- package/dist/esm/createZeroClient.headless.test.native.js.map +1 -1
- package/dist/esm/createZeroClient.httpAuth.test.native.js +1 -1
- package/dist/esm/createZeroClient.httpAuth.test.native.js.map +1 -1
- package/dist/esm/createZeroClient.mjs +21 -3
- package/dist/esm/createZeroClient.mjs.map +1 -1
- package/dist/esm/createZeroClient.native.js +49 -24
- package/dist/esm/createZeroClient.native.js.map +1 -1
- package/dist/esm/createZeroClient.recovery.test.native.js +2 -2
- package/dist/esm/createZeroClient.recovery.test.native.js.map +1 -1
- package/dist/esm/generate-helpers.native.js.map +1 -1
- package/dist/esm/generate-helpers.test.native.js +1 -1
- package/dist/esm/generate-helpers.test.native.js.map +1 -1
- package/dist/esm/generate-layout.native.js.map +1 -1
- package/dist/esm/generate-lite.native.js +1 -1
- package/dist/esm/generate-lite.native.js.map +1 -1
- package/dist/esm/generate-lite.test.native.js +1 -1
- package/dist/esm/generate-lite.test.native.js.map +1 -1
- package/dist/esm/generate.mjs +57 -30
- package/dist/esm/generate.mjs.map +1 -1
- package/dist/esm/generate.native.js +95 -34
- package/dist/esm/generate.native.js.map +1 -1
- package/dist/esm/generate.test.mjs +147 -0
- package/dist/esm/generate.test.mjs.map +1 -1
- package/dist/esm/generate.test.native.js +148 -1
- package/dist/esm/generate.test.native.js.map +1 -1
- package/dist/esm/helpers/NullToOptional.native.js.map +1 -1
- package/dist/esm/helpers/asyncContext.hostStorage.test.native.js +7 -7
- package/dist/esm/helpers/asyncContext.hostStorage.test.native.js.map +1 -1
- package/dist/esm/helpers/batchQuery.native.js +1 -1
- package/dist/esm/helpers/batchQuery.native.js.map +1 -1
- package/dist/esm/helpers/clearZeroClientData.native.js.map +1 -1
- package/dist/esm/helpers/createMutators.native.js +4 -4
- package/dist/esm/helpers/createMutators.native.js.map +1 -1
- package/dist/esm/helpers/createMutators.test.native.js +2 -2
- package/dist/esm/helpers/createMutators.test.native.js.map +1 -1
- package/dist/esm/helpers/ellipsis.native.js.map +1 -1
- package/dist/esm/helpers/emitter.native.js.map +1 -1
- package/dist/esm/helpers/ensure.native.js +1 -1
- package/dist/esm/helpers/ensure.native.js.map +1 -1
- package/dist/esm/helpers/ensureLoggedIn.native.js +2 -2
- package/dist/esm/helpers/ensureLoggedIn.native.js.map +1 -1
- package/dist/esm/helpers/errors.native.js.map +1 -1
- package/dist/esm/helpers/getAuth.native.js +3 -3
- package/dist/esm/helpers/getAuth.native.js.map +1 -1
- package/dist/esm/helpers/getCurrentComponentStack.native.js.map +1 -1
- package/dist/esm/helpers/globalValue.native.js.map +1 -1
- package/dist/esm/helpers/hostStorageScope.native.js.map +1 -1
- package/dist/esm/helpers/mapObject.native.js.map +1 -1
- package/dist/esm/helpers/mutationLifecycle.native.js +1 -1
- package/dist/esm/helpers/mutationLifecycle.native.js.map +1 -1
- package/dist/esm/helpers/mutationLifecycle.test.native.js +1 -1
- package/dist/esm/helpers/mutationLifecycle.test.native.js.map +1 -1
- package/dist/esm/helpers/mutatorContext.native.js +1 -1
- package/dist/esm/helpers/mutatorContext.native.js.map +1 -1
- package/dist/esm/helpers/mutatorContext.test.native.js +6 -6
- package/dist/esm/helpers/mutatorContext.test.native.js.map +1 -1
- package/dist/esm/helpers/prettyFormatZeroQuery.native.js +1 -1
- package/dist/esm/helpers/prettyFormatZeroQuery.native.js.map +1 -1
- package/dist/esm/helpers/queryContext.native.js +1 -1
- package/dist/esm/helpers/queryContext.native.js.map +1 -1
- package/dist/esm/helpers/recoverZeroClient.native.js +1 -1
- package/dist/esm/helpers/recoverZeroClient.native.js.map +1 -1
- package/dist/esm/helpers/recoverZeroClient.test.native.js +2 -2
- package/dist/esm/helpers/recoverZeroClient.test.native.js.map +1 -1
- package/dist/esm/helpers/showZeroClientError.native.js +1 -1
- package/dist/esm/helpers/showZeroClientError.native.js.map +1 -1
- package/dist/esm/helpers/sleep.native.js +1 -1
- package/dist/esm/helpers/sleep.native.js.map +1 -1
- package/dist/esm/helpers/time.native.js.map +1 -1
- package/dist/esm/helpers/tuple.native.js.map +1 -1
- package/dist/esm/helpers/useMutation.native.js.map +1 -1
- package/dist/esm/helpers/useMutation.test.native.js +1 -1
- package/dist/esm/helpers/useMutation.test.native.js.map +1 -1
- package/dist/esm/helpers/useZeroDebug.native.js +2 -2
- package/dist/esm/helpers/useZeroDebug.native.js.map +1 -1
- package/dist/esm/index.native.js +23 -23
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/instanceRegistry.native.js +2 -2
- package/dist/esm/instanceRegistry.native.js.map +1 -1
- package/dist/esm/modelRegistry.native.js.map +1 -1
- package/dist/esm/multi.mjs +10 -5
- package/dist/esm/multi.mjs.map +1 -1
- package/dist/esm/multi.native.js +15 -10
- package/dist/esm/multi.native.js.map +1 -1
- package/dist/esm/multiInstance.test.native.js +10 -10
- package/dist/esm/multiInstance.test.native.js.map +1 -1
- package/dist/esm/multiInstanceMutations.test.native.js +4 -4
- package/dist/esm/multiInstanceMutations.test.native.js.map +1 -1
- package/dist/esm/multiInstanceNested.test.native.js +3 -3
- package/dist/esm/multiInstanceNested.test.native.js.map +1 -1
- package/dist/esm/multiPartition.test.mjs +47 -3
- package/dist/esm/multiPartition.test.mjs.map +1 -1
- package/dist/esm/multiPartition.test.native.js +52 -4
- package/dist/esm/multiPartition.test.native.js.map +1 -1
- package/dist/esm/mutations.native.js +2 -2
- package/dist/esm/mutations.native.js.map +1 -1
- package/dist/esm/mutations.test.native.js +4 -4
- package/dist/esm/mutations.test.native.js.map +1 -1
- package/dist/esm/native-typescript.mjs +50 -11
- package/dist/esm/native-typescript.mjs.map +1 -1
- package/dist/esm/native-typescript.native.js +158 -30
- package/dist/esm/native-typescript.native.js.map +1 -1
- package/dist/esm/provideZero.eagerInstance.test.mjs +22 -0
- package/dist/esm/provideZero.eagerInstance.test.mjs.map +1 -1
- package/dist/esm/provideZero.eagerInstance.test.native.js +31 -1
- package/dist/esm/provideZero.eagerInstance.test.native.js.map +1 -1
- package/dist/esm/provideZero.hydration.test.native.js +2 -2
- package/dist/esm/provideZero.hydration.test.native.js.map +1 -1
- package/dist/esm/provideZero.ssr.test.native.js +2 -2
- package/dist/esm/provideZero.ssr.test.native.js.map +1 -1
- package/dist/esm/queryErrorRecovery.mjs +66 -0
- package/dist/esm/queryErrorRecovery.mjs.map +1 -0
- package/dist/esm/queryErrorRecovery.native.js +175 -0
- package/dist/esm/queryErrorRecovery.native.js.map +1 -0
- package/dist/esm/queryJson.native.js +1 -1
- package/dist/esm/queryJson.native.js.map +1 -1
- package/dist/esm/queryRegistry.native.js.map +1 -1
- package/dist/esm/resolveQuery.native.js +2 -2
- package/dist/esm/resolveQuery.native.js.map +1 -1
- package/dist/esm/run.native.js +4 -4
- package/dist/esm/run.native.js.map +1 -1
- package/dist/esm/server.native.js +10 -10
- package/dist/esm/server.native.js.map +1 -1
- package/dist/esm/server.test.native.js +2 -2
- package/dist/esm/server.test.native.js.map +1 -1
- package/dist/esm/serverWhere.native.js +1 -1
- package/dist/esm/serverWhere.native.js.map +1 -1
- package/dist/esm/serverWhere.test.native.js +3 -3
- package/dist/esm/serverWhere.test.native.js.map +1 -1
- package/dist/esm/state.native.js +1 -1
- package/dist/esm/state.native.js.map +1 -1
- package/dist/esm/streaming.native.js +1 -1
- package/dist/esm/streaming.native.js.map +1 -1
- package/dist/esm/testSetup.native.js.map +1 -1
- package/dist/esm/types.native.js.map +1 -1
- package/dist/esm/usePermission.test.native.js +3 -3
- package/dist/esm/usePermission.test.native.js.map +1 -1
- package/dist/esm/useQuery.aggregate.zero.test.mjs +197 -2
- package/dist/esm/useQuery.aggregate.zero.test.mjs.map +1 -1
- package/dist/esm/useQuery.aggregate.zero.test.native.js +212 -4
- package/dist/esm/useQuery.aggregate.zero.test.native.js.map +1 -1
- package/dist/esm/useQuery.empty.test.native.js +3 -3
- package/dist/esm/useQuery.empty.test.native.js.map +1 -1
- package/dist/esm/useQuery.ssr.test.native.js +2 -2
- package/dist/esm/useQuery.ssr.test.native.js.map +1 -1
- package/dist/esm/useStreamingField.loop.test.native.js +1 -1
- package/dist/esm/useStreamingField.loop.test.native.js.map +1 -1
- package/dist/esm/useStreamingField.native.js.map +1 -1
- package/dist/esm/vite-plugin.mjs +10 -0
- package/dist/esm/vite-plugin.mjs.map +1 -1
- package/dist/esm/vite-plugin.native.js +11 -1
- package/dist/esm/vite-plugin.native.js.map +1 -1
- package/dist/esm/where.native.js +3 -3
- package/dist/esm/where.native.js.map +1 -1
- package/dist/esm/zeroRunner.native.js +1 -1
- package/dist/esm/zeroRunner.native.js.map +1 -1
- package/dist/esm/zql.native.js +1 -1
- package/dist/esm/zql.native.js.map +1 -1
- package/package.json +4 -4
- package/src/cli.ts +6 -0
- package/src/createUseQuery.tsx +20 -5
- package/src/createUseQueryDirect.tsx +17 -1
- package/src/createZeroClient.tsx +37 -4
- package/src/generate.test.ts +116 -0
- package/src/generate.ts +109 -52
- package/src/multi.ts +11 -3
- package/src/multiPartition.test.ts +55 -11
- package/src/native-typescript.ts +64 -11
- package/src/provideZero.eagerInstance.test.tsx +27 -0
- package/src/queryErrorRecovery.ts +95 -0
- package/src/useQuery.aggregate.zero.test.tsx +187 -2
- package/src/vite-plugin.ts +10 -0
- package/types/createUseQuery.d.ts +3 -1
- package/types/createUseQuery.d.ts.map +1 -1
- package/types/createUseQueryDirect.d.ts +3 -1
- package/types/createUseQueryDirect.d.ts.map +1 -1
- package/types/createZeroClient.d.ts +3 -1
- package/types/createZeroClient.d.ts.map +1 -1
- package/types/generate.d.ts +4 -0
- package/types/generate.d.ts.map +1 -1
- package/types/multi.d.ts +3 -1
- package/types/multi.d.ts.map +1 -1
- package/types/native-typescript.d.ts +7 -1
- package/types/native-typescript.d.ts.map +1 -1
- package/types/queryErrorRecovery.d.ts +33 -0
- package/types/queryErrorRecovery.d.ts.map +1 -0
- package/types/useQuery.aggregate.zero.test.d.ts.map +1 -1
- package/types/vite-plugin.d.ts.map +1 -1
package/src/generate.ts
CHANGED
|
@@ -40,7 +40,7 @@ import type { ExtractedMutation, ModelMutations, SchemaColumn } from './generate
|
|
|
40
40
|
import type { DataLayout } from './generate-layout'
|
|
41
41
|
|
|
42
42
|
const hash = (s: string) => createHash('sha256').update(s).digest('hex')
|
|
43
|
-
const GENERATOR_CACHE_VERSION = '
|
|
43
|
+
const GENERATOR_CACHE_VERSION = '10'
|
|
44
44
|
|
|
45
45
|
const isGeneratorSourceFile = (name: string) =>
|
|
46
46
|
name.endsWith('.ts') &&
|
|
@@ -48,13 +48,14 @@ const isGeneratorSourceFile = (name: string) =>
|
|
|
48
48
|
!name.endsWith('.test.ts') &&
|
|
49
49
|
!name.endsWith('.spec.ts')
|
|
50
50
|
|
|
51
|
-
// hash
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
51
|
+
// hash generator inputs plus freshly resolved compiler dependencies. a verified
|
|
52
|
+
// cache hit can skip source AST decoding and parsing, while edits still resolve
|
|
53
|
+
// imported types and validate the generated bytes before reusing them.
|
|
54
|
+
function hashInputTree(
|
|
55
|
+
sourceRoots: string[],
|
|
56
|
+
generatedDir: string,
|
|
57
|
+
dependencyPaths: string[]
|
|
58
|
+
): string {
|
|
58
59
|
const parts: string[] = []
|
|
59
60
|
const seen = new Set<string>()
|
|
60
61
|
const walk = (dir: string) => {
|
|
@@ -80,6 +81,14 @@ function hashInputTree(sourceRoots: string[], generatedDir: string): string {
|
|
|
80
81
|
}
|
|
81
82
|
}
|
|
82
83
|
for (const root of sourceRoots) walk(root)
|
|
84
|
+
// imported types can live outside the data roots, including transitive
|
|
85
|
+
// re-exports and package declarations. use the compiler's resolved inputs.
|
|
86
|
+
for (const path of dependencyPaths) {
|
|
87
|
+
if (seen.has(path) || path.startsWith(`${generatedDir}/`) || !existsSync(path))
|
|
88
|
+
continue
|
|
89
|
+
seen.add(path)
|
|
90
|
+
parts.push(`${path}\0${readFileSync(path, 'utf-8')}`)
|
|
91
|
+
}
|
|
83
92
|
return hash(parts.join('\0'))
|
|
84
93
|
}
|
|
85
94
|
|
|
@@ -447,15 +456,17 @@ async function tsTypeToValibot(
|
|
|
447
456
|
seen = new Set<number>()
|
|
448
457
|
): Promise<string> {
|
|
449
458
|
const checker = project.checker
|
|
450
|
-
// prevent infinite recursion on circular types
|
|
451
|
-
//
|
|
459
|
+
// prevent infinite recursion on circular types. `seen` holds only the
|
|
460
|
+
// structured types (objects, intersections) on the current path, so a type
|
|
461
|
+
// reused by siblings, such as `string[]`, still converts every time.
|
|
452
462
|
const flags = type.flags
|
|
463
|
+
let path = seen
|
|
453
464
|
if (flags & (TypeFlags.Object | TypeFlags.Intersection)) {
|
|
454
465
|
if (seen.has(type.id)) return 'v.unknown()'
|
|
455
|
-
seen.add(type.id)
|
|
466
|
+
path = new Set(seen).add(type.id)
|
|
456
467
|
}
|
|
457
468
|
|
|
458
|
-
const recurse = (value: Type) => tsTypeToValibot(project, value,
|
|
469
|
+
const recurse = (value: Type) => tsTypeToValibot(project, value, path)
|
|
459
470
|
|
|
460
471
|
// primitives
|
|
461
472
|
if (flags & TypeFlags.String) return 'v.string()'
|
|
@@ -741,6 +752,8 @@ export interface GenerateOptions {
|
|
|
741
752
|
dir: string
|
|
742
753
|
/** explicit on-zero.config.ts path; auto-discovered in `dir` when omitted */
|
|
743
754
|
config?: string
|
|
755
|
+
/** generation-only TypeScript project; defaults to each source file's project */
|
|
756
|
+
tsconfig?: string
|
|
744
757
|
/** run after generation */
|
|
745
758
|
after?: string
|
|
746
759
|
/** suppress output */
|
|
@@ -799,20 +812,28 @@ function dataMembershipFromLayout(layout: DataLayout): DataMembership {
|
|
|
799
812
|
}
|
|
800
813
|
}
|
|
801
814
|
|
|
802
|
-
async function loadGeneratorProject(
|
|
815
|
+
async function loadGeneratorProject(
|
|
816
|
+
baseDir: string,
|
|
817
|
+
deferSources = false,
|
|
818
|
+
tsconfig?: string
|
|
819
|
+
): Promise<NativeTypeScriptProject> {
|
|
803
820
|
const sourcePaths = collectTypeScriptSourcePaths([
|
|
804
821
|
baseDir,
|
|
805
822
|
resolve(dirname(baseDir), 'database'),
|
|
806
823
|
])
|
|
807
|
-
return createNativeTypeScriptProject(baseDir, sourcePaths
|
|
824
|
+
return createNativeTypeScriptProject(baseDir, sourcePaths, {
|
|
825
|
+
deferSources,
|
|
826
|
+
tsconfig: tsconfig ? resolve(tsconfig) : undefined,
|
|
827
|
+
})
|
|
808
828
|
}
|
|
809
829
|
|
|
810
830
|
export async function deriveDataMembership(options: {
|
|
811
831
|
dir: string
|
|
812
832
|
config?: string
|
|
833
|
+
tsconfig?: string
|
|
813
834
|
}): Promise<DataMembership> {
|
|
814
835
|
const baseDir = resolve(options.dir)
|
|
815
|
-
const project = await loadGeneratorProject(baseDir)
|
|
836
|
+
const project = await loadGeneratorProject(baseDir, false, options.tsconfig)
|
|
816
837
|
try {
|
|
817
838
|
const layout = discoverDataLayout(
|
|
818
839
|
project,
|
|
@@ -829,9 +850,10 @@ export async function generateDrizzleSchemaInputFile(options: {
|
|
|
829
850
|
dir: string
|
|
830
851
|
schemaImportPath: string
|
|
831
852
|
config?: string
|
|
853
|
+
tsconfig?: string
|
|
832
854
|
}): Promise<string> {
|
|
833
855
|
const baseDir = resolve(options.dir)
|
|
834
|
-
const project = await loadGeneratorProject(baseDir)
|
|
856
|
+
const project = await loadGeneratorProject(baseDir, false, options.tsconfig)
|
|
835
857
|
try {
|
|
836
858
|
return generateDrizzleSchemaInputFileWithProject(options, project)
|
|
837
859
|
} finally {
|
|
@@ -925,7 +947,7 @@ async function generateDrizzleSchemaInputFileWithProject(
|
|
|
925
947
|
}
|
|
926
948
|
|
|
927
949
|
export async function generate(options: GenerateOptions): Promise<GenerateResult> {
|
|
928
|
-
const project = await loadGeneratorProject(resolve(options.dir))
|
|
950
|
+
const project = await loadGeneratorProject(resolve(options.dir), true, options.tsconfig)
|
|
929
951
|
try {
|
|
930
952
|
return await generateWithProject(options, project)
|
|
931
953
|
} finally {
|
|
@@ -947,23 +969,43 @@ async function generateWithProject(
|
|
|
947
969
|
|
|
948
970
|
loadCache()
|
|
949
971
|
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
972
|
+
const configPath = config ? resolve(config) : resolve(baseDir, 'on-zero.config.ts')
|
|
973
|
+
let cachedInputs: Pick<DataLayout, 'sourceRoots' | 'metadataPaths'> | null = null
|
|
974
|
+
if (generateCache.__configPath === configPath) {
|
|
975
|
+
try {
|
|
976
|
+
const value: unknown = JSON.parse(generateCache.__layoutInputs || 'null')
|
|
977
|
+
if (
|
|
978
|
+
value &&
|
|
979
|
+
typeof value === 'object' &&
|
|
980
|
+
'sourceRoots' in value &&
|
|
981
|
+
Array.isArray(value.sourceRoots) &&
|
|
982
|
+
value.sourceRoots.every((path) => typeof path === 'string') &&
|
|
983
|
+
'metadataPaths' in value &&
|
|
984
|
+
Array.isArray(value.metadataPaths) &&
|
|
985
|
+
value.metadataPaths.every((path) => typeof path === 'string')
|
|
986
|
+
) {
|
|
987
|
+
cachedInputs = {
|
|
988
|
+
sourceRoots: value.sourceRoots,
|
|
989
|
+
metadataPaths: value.metadataPaths,
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
} catch {}
|
|
993
|
+
}
|
|
994
|
+
const dependencyPaths = await project.sourceFilePaths()
|
|
995
|
+
const hashInputs = (layout: Pick<DataLayout, 'sourceRoots' | 'metadataPaths'>) => {
|
|
996
|
+
const metadataHash = hash(
|
|
997
|
+
layout.metadataPaths
|
|
998
|
+
.map((path) => `${path}\0${readFileSync(path, 'utf8')}`)
|
|
999
|
+
.join('\0')
|
|
1000
|
+
)
|
|
1001
|
+
return hash(
|
|
1002
|
+
`${hashInputTree(layout.sourceRoots, generatedDir, dependencyPaths)}\0${metadataHash}\0${externalZeroConfig}\0${project.configurationKey}`
|
|
1003
|
+
)
|
|
1004
|
+
}
|
|
962
1005
|
|
|
963
1006
|
// input-freshness gate: if nothing under baseDir changed since the last
|
|
964
|
-
//
|
|
965
|
-
//
|
|
966
|
-
// build entirely and return the cached counts. the configureServer watcher
|
|
1007
|
+
// completed generate, the outputs are already current. resolve compiler inputs
|
|
1008
|
+
// again, but skip source AST loading and return the cached counts. the watcher
|
|
967
1009
|
// still re-runs generate on real model/query edits.
|
|
968
1010
|
const databaseSchemaPath = resolve(dirname(baseDir), 'database/schema.ts')
|
|
969
1011
|
const needsDrizzleSchema = existsSync(databaseSchemaPath)
|
|
@@ -975,34 +1017,24 @@ async function generateWithProject(
|
|
|
975
1017
|
? readFileSync(externalZeroConfigPath, 'utf8')
|
|
976
1018
|
: null
|
|
977
1019
|
const needsSqliteZeroSchema = needsDrizzleSchema && externalZeroConfig === null
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
1020
|
+
let cachedInputHash: string | null = null
|
|
1021
|
+
if (cachedInputs) {
|
|
1022
|
+
try {
|
|
1023
|
+
cachedInputHash = hashInputs(cachedInputs)
|
|
1024
|
+
} catch {}
|
|
1025
|
+
}
|
|
981
1026
|
if (
|
|
982
1027
|
!force &&
|
|
983
1028
|
generateCache.__generatorVersion === GENERATOR_CACHE_VERSION &&
|
|
984
|
-
generateCache.__inputHash ===
|
|
1029
|
+
generateCache.__inputHash === cachedInputHash &&
|
|
985
1030
|
// the input hash deliberately skips the generated directory, so it cannot
|
|
986
1031
|
// notice that the outputs themselves moved. existence is not correctness
|
|
987
1032
|
// either: a checkout, merge or revert leaves every file present and stale.
|
|
988
1033
|
// confirm the bytes on disk still match what the cache says it wrote there
|
|
989
1034
|
// before skipping the build, or the fast path serves someone else's output.
|
|
990
1035
|
//
|
|
991
|
-
//
|
|
992
|
-
//
|
|
993
|
-
// holds the formatted ones. soot does exactly that, `on-zero generate &&
|
|
994
|
-
// generate-instance-tables && oxfmt src/data/generated/`, and the number is
|
|
995
|
-
// already taken: 2.50s median before, 3.69s after, four warm runs each in
|
|
996
|
-
// one checkout with only the pin swapped, so about 1.2 seconds or 47
|
|
997
|
-
// percent on this step. the full three-command script went 2.65s to 3.14s
|
|
998
|
-
// with a spread that swallows most of it.
|
|
999
|
-
//
|
|
1000
|
-
// the shape matters more than the number. this is not a cache that hits
|
|
1001
|
-
// less often, it is a cache that never hits, so the cost does not degrade
|
|
1002
|
-
// gracefully and grows with the generated output rather than staying at
|
|
1003
|
-
// 1.2s. correct and slower beats fast and stale, which is why it is written
|
|
1004
|
-
// this way, but if generate time ever becomes the complaint, record the
|
|
1005
|
-
// hash after the consumer's formatter runs rather than weakening this.
|
|
1036
|
+
// successful after commands record their final output hashes. formatting
|
|
1037
|
+
// therefore keeps the fast path without trusting stale generated bytes.
|
|
1006
1038
|
Object.entries(generateCache).every(([cachedPath, cachedHash]) => {
|
|
1007
1039
|
if (!cachedPath.startsWith(generatedDir)) return true
|
|
1008
1040
|
try {
|
|
@@ -1028,6 +1060,16 @@ async function generateWithProject(
|
|
|
1028
1060
|
}
|
|
1029
1061
|
}
|
|
1030
1062
|
|
|
1063
|
+
// the compiler still resolves current project inputs before the cache check.
|
|
1064
|
+
// only decoding and parsing source ASTs waits until generation is necessary.
|
|
1065
|
+
await project.loadSources()
|
|
1066
|
+
const layout = discoverDataLayout(
|
|
1067
|
+
project,
|
|
1068
|
+
baseDir,
|
|
1069
|
+
config ? resolve(config) : undefined
|
|
1070
|
+
)
|
|
1071
|
+
const inputHash = hashInputs(layout)
|
|
1072
|
+
|
|
1031
1073
|
const modelNamespaces = layout.namespaces.filter(
|
|
1032
1074
|
(namespace): namespace is typeof namespace & { modelPath: string } =>
|
|
1033
1075
|
namespace.modelPath !== null
|
|
@@ -1336,6 +1378,15 @@ async function generateWithProject(
|
|
|
1336
1378
|
stdio: 'inherit',
|
|
1337
1379
|
env: { ...process.env, ON_ZERO_GENERATED_DIR: generatedDir },
|
|
1338
1380
|
})
|
|
1381
|
+
// successful postprocessing owns the final generated bytes. collect all
|
|
1382
|
+
// hashes before updating the cache so a missing output cannot certify a
|
|
1383
|
+
// partially completed postprocessor.
|
|
1384
|
+
const outputHashes = Object.fromEntries(
|
|
1385
|
+
Object.keys(generateCache)
|
|
1386
|
+
.filter((filePath) => filePath.startsWith(generatedDir))
|
|
1387
|
+
.map((filePath) => [filePath, hash(readFileSync(filePath, 'utf-8'))])
|
|
1388
|
+
)
|
|
1389
|
+
Object.assign(generateCache, outputHashes)
|
|
1339
1390
|
} catch (err) {
|
|
1340
1391
|
if (!silent) console.error(`Error running after command: ${err}`)
|
|
1341
1392
|
}
|
|
@@ -1343,6 +1394,11 @@ async function generateWithProject(
|
|
|
1343
1394
|
|
|
1344
1395
|
// record the input hash + counts so the next boot can skip a no-op regen.
|
|
1345
1396
|
generateCache.__generatorVersion = GENERATOR_CACHE_VERSION
|
|
1397
|
+
generateCache.__configPath = configPath
|
|
1398
|
+
generateCache.__layoutInputs = JSON.stringify({
|
|
1399
|
+
sourceRoots: layout.sourceRoots,
|
|
1400
|
+
metadataPaths: layout.metadataPaths,
|
|
1401
|
+
})
|
|
1346
1402
|
generateCache.__inputHash = inputHash
|
|
1347
1403
|
generateCache.__counts = JSON.stringify({
|
|
1348
1404
|
modelCount: modelNamespaces.length,
|
|
@@ -1383,7 +1439,7 @@ export async function watch(options: WatchOptions) {
|
|
|
1383
1439
|
}
|
|
1384
1440
|
|
|
1385
1441
|
const databaseDir = resolve(dirname(baseDir), 'database')
|
|
1386
|
-
const project = await loadGeneratorProject(baseDir)
|
|
1442
|
+
const project = await loadGeneratorProject(baseDir, false, options.tsconfig)
|
|
1387
1443
|
let layout: DataLayout
|
|
1388
1444
|
try {
|
|
1389
1445
|
layout = discoverDataLayout(
|
|
@@ -1398,6 +1454,7 @@ export async function watch(options: WatchOptions) {
|
|
|
1398
1454
|
[
|
|
1399
1455
|
...new Set([
|
|
1400
1456
|
...layout.sourceRoots,
|
|
1457
|
+
...(options.tsconfig ? [resolve(options.tsconfig)] : []),
|
|
1401
1458
|
...(existsSync(databaseDir) ? [databaseDir] : []),
|
|
1402
1459
|
]),
|
|
1403
1460
|
],
|
package/src/multi.ts
CHANGED
|
@@ -55,7 +55,7 @@ type ClientUnion<Instances extends Record<string, ZeroInstanceManifestEntry>> =
|
|
|
55
55
|
|
|
56
56
|
export function createZeroClients<
|
|
57
57
|
const Instances extends Record<string, ZeroInstanceManifestEntry>,
|
|
58
|
-
>(instances: Instances) {
|
|
58
|
+
>(instances: Instances, options: { inner: keyof Instances & string }) {
|
|
59
59
|
const names = Object.keys(instances)
|
|
60
60
|
if (names.length === 0) {
|
|
61
61
|
throw new Error('[on-zero] createZeroClients requires at least one instance')
|
|
@@ -65,7 +65,12 @@ export function createZeroClients<
|
|
|
65
65
|
names.unshift('default')
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
const innerName =
|
|
68
|
+
const innerName = options.inner
|
|
69
|
+
if (!names.includes(innerName)) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
`[on-zero] createZeroClients inner instance '${innerName}' is not in the manifest`
|
|
72
|
+
)
|
|
73
|
+
}
|
|
69
74
|
const clients: Record<string, ReturnType<typeof createZeroClientInternal>> = {}
|
|
70
75
|
|
|
71
76
|
// release the complete old partition atomically before any new instance
|
|
@@ -99,6 +104,9 @@ export function createZeroClients<
|
|
|
99
104
|
return {
|
|
100
105
|
clients: typedClients,
|
|
101
106
|
providers,
|
|
102
|
-
combined: combineZeroClients(
|
|
107
|
+
combined: combineZeroClients<[ClientUnion<Instances>, ...ClientUnion<Instances>[]]>(
|
|
108
|
+
...orderedClients,
|
|
109
|
+
{ inner: innerName }
|
|
110
|
+
),
|
|
103
111
|
}
|
|
104
112
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createSchema, string, table } from '@rocicorp/zero'
|
|
2
|
-
import { describe, expect, test } from 'vitest'
|
|
2
|
+
import { describe, expect, test, vi } from 'vitest'
|
|
3
3
|
|
|
4
|
+
import { getInstanceForQueryFn } from './instanceRegistry'
|
|
4
5
|
import { createZeroClients } from './multi'
|
|
5
6
|
|
|
6
7
|
const schema = createSchema({
|
|
@@ -32,7 +33,7 @@ describe('createZeroClients', () => {
|
|
|
32
33
|
},
|
|
33
34
|
} as const
|
|
34
35
|
|
|
35
|
-
const result = createZeroClients(instances)
|
|
36
|
+
const result = createZeroClients(instances, { inner: 'default' })
|
|
36
37
|
|
|
37
38
|
expect(Object.keys(result.clients)).toEqual(['project', 'default'])
|
|
38
39
|
expect(result.clients.default.instanceName).toBe('default')
|
|
@@ -40,10 +41,47 @@ describe('createZeroClients', () => {
|
|
|
40
41
|
expect(result.providers.default).toBe(result.clients.default.ProvideZero)
|
|
41
42
|
expect(result.providers.project).toBe(result.clients.project.ProvideZero)
|
|
42
43
|
expect(result.combined.run).toBeTypeOf('function')
|
|
44
|
+
|
|
45
|
+
const innerQuery = vi
|
|
46
|
+
.spyOn(result.clients.default, 'useQuery')
|
|
47
|
+
.mockReturnValue('inner' as never)
|
|
48
|
+
const outerQuery = vi
|
|
49
|
+
.spyOn(result.clients.project, 'useQueryDirect')
|
|
50
|
+
.mockReturnValue('outer' as never)
|
|
51
|
+
expect(result.combined.useQuery(instances.default.queries.account.current, {})).toBe(
|
|
52
|
+
'inner'
|
|
53
|
+
)
|
|
54
|
+
expect(result.combined.useQuery(instances.project.queries.message.all, {})).toBe(
|
|
55
|
+
'outer'
|
|
56
|
+
)
|
|
57
|
+
expect(innerQuery).toHaveBeenCalledOnce()
|
|
58
|
+
expect(outerQuery).toHaveBeenCalledOnce()
|
|
43
59
|
})
|
|
44
60
|
|
|
45
61
|
test('requires at least one generated instance', () => {
|
|
46
|
-
expect(() => createZeroClients({})).toThrow(
|
|
62
|
+
expect(() => createZeroClients({}, { inner: 'missing' as never })).toThrow(
|
|
63
|
+
/at least one instance/
|
|
64
|
+
)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
test('rejects an unknown inner instance before replacing registered clients', () => {
|
|
68
|
+
const entry = {
|
|
69
|
+
schema,
|
|
70
|
+
queries: { preserved: { current: () => ({}) as never } },
|
|
71
|
+
models: {},
|
|
72
|
+
tables: [],
|
|
73
|
+
syncTables: [],
|
|
74
|
+
supportTables: [],
|
|
75
|
+
scope: null,
|
|
76
|
+
defaultVisibility: null,
|
|
77
|
+
}
|
|
78
|
+
createZeroClients({ default: entry }, { inner: 'default' })
|
|
79
|
+
const owner = getInstanceForQueryFn(entry.queries.preserved.current)
|
|
80
|
+
expect(owner?.name).toBe('default')
|
|
81
|
+
expect(() =>
|
|
82
|
+
createZeroClients({ default: entry }, { inner: 'missing' as never })
|
|
83
|
+
).toThrow(/inner instance 'missing'/)
|
|
84
|
+
expect(getInstanceForQueryFn(entry.queries.preserved.current)).toBe(owner)
|
|
47
85
|
})
|
|
48
86
|
|
|
49
87
|
test('replaces an existing partition atomically when a namespace moves', () => {
|
|
@@ -58,16 +96,22 @@ describe('createZeroClients', () => {
|
|
|
58
96
|
defaultVisibility: null,
|
|
59
97
|
})
|
|
60
98
|
|
|
61
|
-
createZeroClients(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
99
|
+
createZeroClients(
|
|
100
|
+
{
|
|
101
|
+
default: entry({ movedNamespace: { before: () => ({}) as never } }),
|
|
102
|
+
project: entry({ stableProject: { before: () => ({}) as never } }),
|
|
103
|
+
},
|
|
104
|
+
{ inner: 'project' }
|
|
105
|
+
)
|
|
65
106
|
|
|
66
107
|
expect(() =>
|
|
67
|
-
createZeroClients(
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
108
|
+
createZeroClients(
|
|
109
|
+
{
|
|
110
|
+
default: entry({ stableDefault: { after: () => ({}) as never } }),
|
|
111
|
+
project: entry({ movedNamespace: { after: () => ({}) as never } }),
|
|
112
|
+
},
|
|
113
|
+
{ inner: 'project' }
|
|
114
|
+
)
|
|
71
115
|
).not.toThrow()
|
|
72
116
|
})
|
|
73
117
|
})
|
package/src/native-typescript.ts
CHANGED
|
@@ -9,7 +9,10 @@ import type { SourceFile } from 'typescript/unstable/ast'
|
|
|
9
9
|
process.env.GOMAXPROCS ??= '2'
|
|
10
10
|
|
|
11
11
|
export type NativeTypeScriptProject = {
|
|
12
|
+
configurationKey: string
|
|
12
13
|
projectForFile(path: string): Project
|
|
14
|
+
sourceFilePaths(): Promise<string[]>
|
|
15
|
+
loadSources(): Promise<void>
|
|
13
16
|
sourceFile(path: string): SourceFile
|
|
14
17
|
hasParseErrors(path: string): boolean
|
|
15
18
|
close(): Promise<void>
|
|
@@ -19,6 +22,7 @@ type CompilerSession = {
|
|
|
19
22
|
api: API
|
|
20
23
|
paths: Set<string>
|
|
21
24
|
root: string
|
|
25
|
+
tsconfig?: string
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
let compiler: CompilerSession | null = null
|
|
@@ -30,7 +34,9 @@ async function closeCompiler(session: CompilerSession) {
|
|
|
30
34
|
try {
|
|
31
35
|
if (session.paths.size > 0) {
|
|
32
36
|
const snapshot = await session.api.updateSnapshot({
|
|
33
|
-
|
|
37
|
+
...(session.tsconfig
|
|
38
|
+
? { closeProjects: [session.tsconfig] }
|
|
39
|
+
: { closeFiles: [...session.paths] }),
|
|
34
40
|
})
|
|
35
41
|
await snapshot.dispose()
|
|
36
42
|
}
|
|
@@ -39,7 +45,7 @@ async function closeCompiler(session: CompilerSession) {
|
|
|
39
45
|
}
|
|
40
46
|
}
|
|
41
47
|
|
|
42
|
-
async function acquireCompiler(root: string, sourcePaths: string[]) {
|
|
48
|
+
async function acquireCompiler(root: string, sourcePaths: string[], tsconfig?: string) {
|
|
43
49
|
const previousTurn = compilerTurn
|
|
44
50
|
let releaseTurn = () => {}
|
|
45
51
|
compilerTurn = new Promise<void>((resolveTurn) => {
|
|
@@ -51,26 +57,31 @@ async function acquireCompiler(root: string, sourcePaths: string[]) {
|
|
|
51
57
|
compilerCloseTimer = null
|
|
52
58
|
}
|
|
53
59
|
if (compilerClose) await compilerClose
|
|
54
|
-
|
|
60
|
+
// configured projects cache their root membership. reopen after generation
|
|
61
|
+
// adds files so a following run includes those outputs in its new program.
|
|
62
|
+
if (
|
|
63
|
+
compiler &&
|
|
64
|
+
(tsconfig || compiler.root !== root || compiler.tsconfig !== tsconfig)
|
|
65
|
+
) {
|
|
55
66
|
const previous = compiler
|
|
56
67
|
compiler = null
|
|
57
68
|
await closeCompiler(previous)
|
|
58
69
|
}
|
|
59
|
-
compiler ??= { api: new API({ cwd: root }), paths: new Set(), root }
|
|
70
|
+
compiler ??= { api: new API({ cwd: root }), paths: new Set(), root, tsconfig }
|
|
60
71
|
compiler.api.clearSourceFileCache()
|
|
61
72
|
const previousPaths = compiler.paths
|
|
62
73
|
const nextPaths = new Set(sourcePaths)
|
|
63
74
|
compiler.paths = nextPaths
|
|
64
75
|
if (previousPaths.size > 0) {
|
|
65
76
|
const closedSnapshot = await compiler.api.updateSnapshot({
|
|
66
|
-
closeFiles: [...previousPaths],
|
|
77
|
+
...(tsconfig ? { closeProjects: [tsconfig] } : { closeFiles: [...previousPaths] }),
|
|
67
78
|
fileChanges: { invalidateAll: true },
|
|
68
79
|
})
|
|
69
80
|
await closedSnapshot.dispose()
|
|
70
81
|
compiler.api.clearSourceFileCache()
|
|
71
82
|
}
|
|
72
83
|
const snapshot = await compiler.api.updateSnapshot({
|
|
73
|
-
openFiles: sourcePaths,
|
|
84
|
+
...(tsconfig ? { openProjects: [tsconfig] } : { openFiles: sourcePaths }),
|
|
74
85
|
fileChanges: { invalidateAll: true },
|
|
75
86
|
})
|
|
76
87
|
compiler.api.clearSourceFileCache()
|
|
@@ -115,25 +126,30 @@ export function collectTypeScriptSourcePaths(roots: string[]): string[] {
|
|
|
115
126
|
|
|
116
127
|
export async function createNativeTypeScriptProject(
|
|
117
128
|
root: string,
|
|
118
|
-
sourcePaths: string[]
|
|
129
|
+
sourcePaths: string[],
|
|
130
|
+
options: { deferSources?: boolean; tsconfig?: string } = {}
|
|
119
131
|
): Promise<NativeTypeScriptProject> {
|
|
120
132
|
if (sourcePaths.length === 0) {
|
|
121
133
|
throw new Error(`[on-zero] no TypeScript source files found under ${root}`)
|
|
122
134
|
}
|
|
123
135
|
|
|
124
|
-
const { session, snapshot, releaseTurn } = await acquireCompiler(
|
|
136
|
+
const { session, snapshot, releaseTurn } = await acquireCompiler(
|
|
137
|
+
root,
|
|
138
|
+
sourcePaths,
|
|
139
|
+
options.tsconfig
|
|
140
|
+
)
|
|
125
141
|
const sources = new Map<string, SourceFile>()
|
|
126
142
|
const projectsByFile = new Map<string, Project>()
|
|
127
143
|
const parseErrors = new Set<string>()
|
|
128
144
|
|
|
129
|
-
|
|
145
|
+
const loadSources = async () => {
|
|
130
146
|
for (const path of sourcePaths) {
|
|
131
|
-
|
|
147
|
+
if (sources.has(path)) continue
|
|
148
|
+
const project = projectsByFile.get(path)
|
|
132
149
|
if (!project) throw new Error(`[on-zero] TypeScript did not open ${path}`)
|
|
133
150
|
const source = await project.program.getSourceFile(path)
|
|
134
151
|
if (!source) throw new Error(`[on-zero] TypeScript did not parse ${path}`)
|
|
135
152
|
sources.set(path, source)
|
|
136
|
-
projectsByFile.set(path, project)
|
|
137
153
|
try {
|
|
138
154
|
parse(readFileSync(path, 'utf8'), {
|
|
139
155
|
plugins: ['jsx', 'typescript'],
|
|
@@ -143,6 +159,29 @@ export async function createNativeTypeScriptProject(
|
|
|
143
159
|
parseErrors.add(path)
|
|
144
160
|
}
|
|
145
161
|
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
try {
|
|
165
|
+
const scopedProject = options.tsconfig
|
|
166
|
+
? snapshot.getProject(options.tsconfig)
|
|
167
|
+
: undefined
|
|
168
|
+
if (options.tsconfig) {
|
|
169
|
+
if (!scopedProject)
|
|
170
|
+
throw new Error(`[on-zero] TypeScript did not open ${options.tsconfig}`)
|
|
171
|
+
const included = new Set(await scopedProject.program.getSourceFileNames())
|
|
172
|
+
for (const path of sourcePaths) {
|
|
173
|
+
if (!included.has(path))
|
|
174
|
+
throw new Error(`[on-zero] generation project does not include ${path}`)
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
for (const path of sourcePaths) {
|
|
178
|
+
const project = options.tsconfig
|
|
179
|
+
? scopedProject
|
|
180
|
+
: await snapshot.getDefaultProjectForFile(path)
|
|
181
|
+
if (!project) throw new Error(`[on-zero] TypeScript did not open ${path}`)
|
|
182
|
+
projectsByFile.set(path, project)
|
|
183
|
+
}
|
|
184
|
+
if (!options.deferSources) await loadSources()
|
|
146
185
|
} catch (error) {
|
|
147
186
|
await snapshot.dispose()
|
|
148
187
|
releaseCompiler(session, releaseTurn)
|
|
@@ -151,6 +190,20 @@ export async function createNativeTypeScriptProject(
|
|
|
151
190
|
|
|
152
191
|
let closed = false
|
|
153
192
|
return {
|
|
193
|
+
configurationKey: JSON.stringify(
|
|
194
|
+
[...new Map([...projectsByFile.values()].map((p) => [p.id, p])).values()]
|
|
195
|
+
.map((project) => [project.configFileName, project.compilerOptions])
|
|
196
|
+
.sort(([left], [right]) => String(left).localeCompare(String(right)))
|
|
197
|
+
),
|
|
198
|
+
loadSources,
|
|
199
|
+
async sourceFilePaths() {
|
|
200
|
+
const paths = new Set<string>()
|
|
201
|
+
const projects = new Map([...projectsByFile.values()].map((p) => [p.id, p]))
|
|
202
|
+
for (const project of projects.values()) {
|
|
203
|
+
for (const path of await project.program.getSourceFileNames()) paths.add(path)
|
|
204
|
+
}
|
|
205
|
+
return [...paths].sort()
|
|
206
|
+
},
|
|
154
207
|
projectForFile(path) {
|
|
155
208
|
const project = projectsByFile.get(resolve(path))
|
|
156
209
|
if (!project)
|
|
@@ -233,3 +233,30 @@ test('disable=true constructs nothing', () => {
|
|
|
233
233
|
|
|
234
234
|
expect(fakeZero.instances.length).toBe(0)
|
|
235
235
|
})
|
|
236
|
+
|
|
237
|
+
test('unmounting one of two overlapping providers keeps the shared instance published', () => {
|
|
238
|
+
const client = makeClient()
|
|
239
|
+
const first = createRoot(document.createElement('div'))
|
|
240
|
+
root = createRoot(container)
|
|
241
|
+
const mount = (target: Root | null) =>
|
|
242
|
+
act(() => {
|
|
243
|
+
target?.render(
|
|
244
|
+
<client.ProvideZero cacheURL="http://127.0.0.1:7788/zero" userID="shared">
|
|
245
|
+
<span>ok</span>
|
|
246
|
+
</client.ProvideZero>
|
|
247
|
+
)
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
mount(first)
|
|
251
|
+
mount(root)
|
|
252
|
+
expect(fakeZero.instances.length).toBe(1)
|
|
253
|
+
|
|
254
|
+
act(() => first.unmount())
|
|
255
|
+
expect((client.zero as unknown as { clientID: string }).clientID).toBe(
|
|
256
|
+
fakeZero.instances[0].clientID
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
act(() => root?.unmount())
|
|
260
|
+
root = null
|
|
261
|
+
expect(() => client.zero.clientID).toThrow(/Zero instance not initialized/)
|
|
262
|
+
})
|