Skip to content

Commit

Permalink
Merge pull request #4532 from Shopify/fix-contract-schema-parsing
Browse files Browse the repository at this point in the history
Clean up extension config
  • Loading branch information
reemrazak authored Oct 1, 2024
2 parents cd9c393 + 64fa18e commit 90e17ce
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 5 deletions.
4 changes: 3 additions & 1 deletion packages/app/src/cli/models/app/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,9 @@ class AppLoader<TConfig extends AppConfiguration, TModuleSpec extends ExtensionS
const configuration = await this.parseConfigurationFile(UnifiedSchema, configurationPath)
const extensionsInstancesPromises = configuration.extensions.map(async (extensionConfig) => {
const mergedConfig = {...configuration, ...extensionConfig}
const {extensions, ...restConfig} = mergedConfig

// Remove `extensions` and `path`, they are injected automatically but not needed nor expected by the contract
const {extensions, path, ...restConfig} = mergedConfig
if (!restConfig.handle) {
// Handle is required for unified config extensions.
this.abortOrReport(
Expand Down
5 changes: 4 additions & 1 deletion packages/app/src/cli/models/extensions/specification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,10 @@ export function createContractBasedModuleSpecification<TConfiguration extends Ba
schema: zod.any({}) as unknown as ZodSchemaType<TConfiguration>,
appModuleFeatures: () => appModuleFeatures ?? [],
deployConfig: async (config, _) => {
return config
// These are loaded automatically for all modules, but are considered "first class" and not part of extension contracts
// If a module needs them, they can access them from the manifest.
const {type, handle, uid, ...configWithoutFirstClassFields} = config
return configWithoutFirstClassFields
},
})
}
Expand Down
5 changes: 4 additions & 1 deletion packages/app/src/cli/services/dev/update-extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,10 @@ export async function reloadExtensionConfig({extension}: UpdateExtensionConfigOp
)
}

configObject = {...configuration, ...extensionConfig}
const mergedConfig = {...configuration, ...extensionConfig}
// Remove `extensions` and `path`, they are injected automatically but not needed nor expected by the contract
const {extensions, path, ...restConfig} = mergedConfig
configObject = restConfig
}

const newConfig = await parseConfigurationObjectAgainstSpecification(
Expand Down
9 changes: 7 additions & 2 deletions packages/app/src/cli/utilities/json-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,13 @@ export async function unifiedConfigurationParserFactory(

// Then, even if this failed, we try to validate against the contract.
const zodValidatedData = zodParse.state === 'ok' ? zodParse.data : undefined
const subjectForAjv = zodValidatedData ?? config
const jsonSchemaParse = jsonSchemaValidate(subjectForAjv, contract)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const subjectForAjv = zodValidatedData ?? (config as any)

// These are loaded automatically for all modules, but are considered "first class" and not part of extension contracts
// If a module needs them, they can access them from the manifest.
const {type, handle, uid, ...subjectForAjvWithoutFirstClassFields} = subjectForAjv
const jsonSchemaParse = jsonSchemaValidate(subjectForAjvWithoutFirstClassFields, contract)

// Finally, we de-duplicate the error set from both validations -- identical messages for identical paths are removed
let errors = zodParse.errors || []
Expand Down

0 comments on commit 90e17ce

Please sign in to comment.