-
Notifications
You must be signed in to change notification settings - Fork 111
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add decomposition preset for external service registration (#1493)
* chore: wip * chore: license year * chore(release): 12.11.0 [skip ci] * chore: only check md file (#1475) * fix: add workflow flow actions to decomposed workflow preset and allow isAddressable (#1467) * fix: add workflow flow actions and allow isAddressable * fix: add workflow flow actions * chore(release): 12.11.1 [skip ci] * W-17279149 Register MD APIs to metadata registry (#1472) * chore: register md apis to metadata registry * Update metadataRegistry.json chore:empty commit * chore(release): 12.11.2 [skip ci] * chore: auto-update metadata coverage in METADATA_SUPPORT.md [no ci] * fix: update snapshot (#1478) * chore(release): 12.11.3 [skip ci] * feat(mdTypes): register tua viz and ws metadata types (#1479) * chore(release): 12.12.0 [skip ci] * chore: auto-update metadata coverage in METADATA_SUPPORT.md [no ci] * fix: resolve strict dirs before suffixes for potential metadata files (#1480) * fix: resolve strict dirs before suffixes for potential metadata files * fix: do not reuse suffixType if no match * chore(release): 12.12.1 [skip ci] * chore: wip * chore: wip * chore: wip * chore: encoded in MD, chars in SD (#1485) * chore: wip * chore: wip * chore: update md xml to include xml header * chore: temp (#1490) * chore: wip * Wr/decompose esr (#1492) * chore: reset snapshots to main * fix: deploy ESR yaml and -meta * test: fix registry test * chore: bump core * chore: always decompose to yaml The schema property contents in an esr can be either yaml of json. For simplicity, given the property alwasy represents an Open API spec, the decomposed format of schema will be yaml. Recomposition will use an existing xml property, schemaUploadFileExtension, to determine the format when build the MD type. * chore: add missing expected artifacts --------- Co-authored-by: peternhale <peter.hale@salesforce.com> * chore: fix test * chore: address review suggestions --------- Co-authored-by: Willhoit <iowillhoit@users.noreply.github.com> Co-authored-by: svc-cli-bot <Svc_cli_bot@salesforce.com> Co-authored-by: Matt Carvin <90224411+mcarvin8@users.noreply.github.com> Co-authored-by: Idan Roas <44600753+IdanRoas@users.noreply.github.com> Co-authored-by: Willie Ruemmele <willieruemmele@gmail.com> Co-authored-by: PKV <43024336+PraveenViswanathan@users.noreply.github.com> Co-authored-by: Steve Hetzel <shetzel@salesforce.com>
- Loading branch information
1 parent
f2b53e1
commit dc7d20e
Showing
50 changed files
with
2,188 additions
and
2,453 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50 changes: 50 additions & 0 deletions
50
src/convert/convertContext/decomposedExternalServiceRegistrationFinalizer.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/* | ||
* Copyright (c) 2025, salesforce.com, inc. | ||
* All rights reserved. | ||
* Licensed under the BSD 3-Clause license. | ||
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause | ||
*/ | ||
import { join } from 'node:path'; | ||
import type { ExternalServiceRegistration } from '@jsforce/jsforce-node/lib/api/metadata/schema'; | ||
import { ensure, ensureString } from '@salesforce/ts-types'; | ||
import { WriterFormat } from '../types'; | ||
import { MetadataType } from '../../registry'; | ||
import { JsToXml } from '../streams'; | ||
import { ConvertTransactionFinalizer } from './transactionFinalizer'; | ||
|
||
type ExternalServiceRegistrationState = { | ||
esrRecords: Map<string, ExternalServiceRegistration>; | ||
}; | ||
|
||
export class DecomposedExternalServiceRegistrationFinalizer extends ConvertTransactionFinalizer<ExternalServiceRegistrationState> { | ||
/** to support custom presets (the only way this code should get hit at all pass in the type from a transformer that has registry access */ | ||
public externalServiceRegistration?: MetadataType; | ||
public transactionState: ExternalServiceRegistrationState = { | ||
esrRecords: new Map<string, ExternalServiceRegistration>(), | ||
}; | ||
// eslint-disable-next-line class-methods-use-this | ||
public defaultDir: string | undefined; | ||
|
||
public finalize(defaultDirectory: string | undefined): Promise<WriterFormat[]> { | ||
this.defaultDir = defaultDirectory; | ||
const writerFormats: WriterFormat[] = []; | ||
this.transactionState.esrRecords.forEach((esrRecord, parent) => | ||
writerFormats.push({ | ||
component: { | ||
type: ensure(this.externalServiceRegistration, 'DecomposedESRFinalizer should have set .ESR'), | ||
fullName: ensureString(parent), | ||
}, | ||
writeInfos: [ | ||
{ | ||
output: join( | ||
ensure(this.externalServiceRegistration?.directoryName, 'directory name missing'), | ||
`${parent}.externalServiceRegistration` | ||
), | ||
source: new JsToXml({ ExternalServiceRegistration: { ...esrRecord } }), | ||
}, | ||
], | ||
}) | ||
); | ||
return Promise.resolve(writerFormats); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
119 changes: 119 additions & 0 deletions
119
src/convert/transformers/decomposeExternalServiceRegistrationTransformer.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
/* | ||
* Copyright (c) 2023, salesforce.com, inc. | ||
* All rights reserved. | ||
* Licensed under the BSD 3-Clause license. | ||
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause | ||
*/ | ||
import * as path from 'node:path'; | ||
import { Readable } from 'node:stream'; | ||
import * as yaml from 'yaml'; | ||
import { XMLBuilder } from 'fast-xml-parser'; | ||
import type { ExternalServiceRegistration } from '@jsforce/jsforce-node/lib/api/metadata/schema'; | ||
import { WriteInfo } from '../types'; | ||
import { SourceComponent } from '../../resolve'; | ||
import { DEFAULT_PACKAGE_ROOT_SFDX, META_XML_SUFFIX, XML_DECL, XML_NS_KEY } from '../../common'; | ||
import { BaseMetadataTransformer } from './baseMetadataTransformer'; | ||
|
||
type SchemaType = 'json' | 'yaml'; | ||
|
||
type ESR = { | ||
ExternalServiceRegistration: ExternalServiceRegistration & { schemaUploadFileExtension: SchemaType }; | ||
}; | ||
|
||
const xmlDeclaration = '<?xml version="1.0" encoding="UTF-8"?>\n'; | ||
|
||
export class DecomposeExternalServiceRegistrationTransformer extends BaseMetadataTransformer { | ||
public async toSourceFormat(input: { | ||
component: SourceComponent; | ||
mergeWith?: SourceComponent | undefined; | ||
}): Promise<WriteInfo[]> { | ||
this.context.decomposedExternalServiceRegistration.externalServiceRegistration ??= | ||
this.registry.getTypeByName('ExternalServiceRegistration'); | ||
const writeInfos: WriteInfo[] = []; | ||
const { component } = input; | ||
const outputDir = path.join( | ||
this.getOutputFolder('source', component), | ||
this.context.decomposedExternalServiceRegistration.externalServiceRegistration.directoryName | ||
); | ||
const xmlContent = { ...(await component.parseXml<ESR>()).ExternalServiceRegistration }; | ||
|
||
// Extract schema content | ||
const schemaContent: string = xmlContent.schema ?? ''; | ||
const schemaType = xmlContent.schemaUploadFileExtension ?? this.getSchemaType(schemaContent); | ||
const asYaml = schemaType === 'yaml' ? schemaContent : yaml.stringify(JSON.parse(schemaContent)); | ||
const schemaFileName = `${component.fullName}.yaml`; | ||
const schemaFilePath = path.join(path.dirname(outputDir), schemaFileName); | ||
|
||
// make sure the schema type is set | ||
xmlContent.schemaUploadFileExtension = schemaType; | ||
|
||
// Write schema content to file | ||
writeInfos.push({ | ||
source: Readable.from(asYaml), | ||
output: schemaFilePath, | ||
}); | ||
|
||
// Remove schema content from ESR content | ||
delete xmlContent.schema; | ||
|
||
// Write remaining ESR content to file | ||
const esrFileName = `${component.fullName}.externalServiceRegistration`; | ||
const esrFilePath = path.join(path.dirname(outputDir), `${esrFileName}${META_XML_SUFFIX}`); | ||
const xmlBuilder = new XMLBuilder({ | ||
format: true, | ||
ignoreAttributes: false, | ||
suppressUnpairedNode: true, | ||
processEntities: true, | ||
indentBy: ' ', | ||
}); | ||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment | ||
const source = xmlBuilder.build({ ExternalServiceRegistration: xmlContent }); | ||
writeInfos.push({ | ||
source: Readable.from(Buffer.from(xmlDeclaration + source)), | ||
output: esrFilePath, | ||
}); | ||
|
||
return writeInfos; | ||
} | ||
|
||
public async toMetadataFormat(component: SourceComponent): Promise<WriteInfo[]> { | ||
// only need to do this once | ||
this.context.decomposedExternalServiceRegistration.externalServiceRegistration ??= | ||
this.registry.getTypeByName('ExternalServiceRegistration'); | ||
const esrFilePath = component.xml; | ||
const esrContent = { ...(await component.parseXml<ESR>()).ExternalServiceRegistration }; | ||
|
||
// Read schema content from file | ||
const schemaFileName = `${component.fullName}.yaml`; // or .json based on your logic | ||
const schemaFilePath = path.join(path.dirname(esrFilePath ?? ''), schemaFileName); | ||
// load the schema content from the file | ||
const schemaContent = (await component.tree.readFile(schemaFilePath)).toString(); | ||
// Add schema content back to ESR content in its original format | ||
// if the original format was JSON, then convert the yaml to json otherwise leave as is | ||
esrContent.schema = | ||
esrContent.schemaUploadFileExtension === 'json' | ||
? JSON.stringify(yaml.parse(schemaContent), undefined, 2) | ||
: schemaContent; | ||
|
||
// Write combined content back to md format | ||
this.context.decomposedExternalServiceRegistration.transactionState.esrRecords.set(component.fullName, { | ||
// @ts-expect-error Object literal may only specify known properties | ||
[XML_NS_KEY]: XML_DECL, | ||
...esrContent, | ||
}); | ||
|
||
return []; | ||
} | ||
|
||
// eslint-disable-next-line class-methods-use-this | ||
private getOutputFolder(format: string, component: SourceComponent, mergeWith?: SourceComponent): string { | ||
const base = format === 'source' ? DEFAULT_PACKAGE_ROOT_SFDX : ''; | ||
const { type } = mergeWith ?? component; | ||
return path.join(base, type.directoryName); | ||
} | ||
|
||
// eslint-disable-next-line class-methods-use-this | ||
private getSchemaType(content: string): SchemaType { | ||
return content.trim().startsWith('{') ? 'json' : 'yaml'; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
43 changes: 43 additions & 0 deletions
43
src/registry/presets/decomposeExternalServiceRegistrationBeta.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
{ | ||
"types": { | ||
"externalserviceregistration": { | ||
"children": { | ||
"types": { | ||
"yaml": { | ||
"strategies": { | ||
"adapter": "partiallyDecomposed" | ||
}, | ||
"directoryName": "externalServiceRegistrations", | ||
"id": "yaml", | ||
"isAddressable": false, | ||
"name": "OAS Yaml Schema", | ||
"suffix": "yaml", | ||
"xmlElementName": "schema" | ||
} | ||
}, | ||
"suffixes": { | ||
"yaml": "yaml" | ||
} | ||
}, | ||
"directoryName": "externalServiceRegistrations", | ||
"id": "externalserviceregistration", | ||
"ignoreParsedFullName": false, | ||
"name": "ExternalServiceRegistration", | ||
"strategies": { | ||
"adapter": "partiallyDecomposed", | ||
"decomposition": "topLevel", | ||
"transformer": "decomposeExternalServiceRegistration" | ||
}, | ||
"suffix": "externalServiceRegistration", | ||
"supportsPartialDelete": false | ||
} | ||
}, | ||
"suffixes": { | ||
"yaml": "yaml", | ||
"externalServiceRegistration": "externalserviceregistration" | ||
}, | ||
"strictDirectoryNames": {}, | ||
"childTypes": { | ||
"yaml": "externalserviceregistration" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.