From 42eb6d7bc7e1fe6df08a8cdd8250d9e2b050f662 Mon Sep 17 00:00:00 2001 From: mshanemc Date: Thu, 1 Aug 2024 16:35:32 -0500 Subject: [PATCH] refactor: shared posixify fn for windows ut --- src/client/deployMessages.ts | 4 +++- src/client/metadataApiDeploy.ts | 4 ++-- src/convert/replacements.ts | 7 +++---- src/convert/streams.ts | 4 ++-- .../staticResourceMetadataTransformer.ts | 5 ++--- src/utils/path.ts | 3 +++ test/convert/replacements.test.ts | 20 +++++++++---------- test/mock/client/index.ts | 8 +++----- 8 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/client/deployMessages.ts b/src/client/deployMessages.ts index 799eda9780..79f2eb646b 100644 --- a/src/client/deployMessages.ts +++ b/src/client/deployMessages.ts @@ -8,6 +8,7 @@ import { basename, dirname, extname, join, posix, sep } from 'node:path/posix'; import { SfError } from '@salesforce/core'; import { ensureArray } from '@salesforce/kit'; +import { posixify } from '../utils/path'; import { ComponentLike, SourceComponent } from '../resolve'; import { registry } from '../registry/registry'; import { @@ -154,8 +155,9 @@ const hasComponentType = (message: DeployMessage): message is DeployMessage & { export const toKey = (component: ComponentLike): string => { const type = typeof component.type === 'string' ? component.type : component.type.name; - return `${type}#${shouldConvertPaths ? component.fullName.split(sep).join(posix.sep) : component.fullName}`; + return `${type}#${shouldConvertPaths ? posixify(component.fullName) : component.fullName}`; }; const isTrue = (value: BooleanString): boolean => value === 'true' || value === true; + export const shouldConvertPaths = sep !== posix.sep; diff --git a/src/client/metadataApiDeploy.ts b/src/client/metadataApiDeploy.ts index 51dc67563e..8a134ee082 100644 --- a/src/client/metadataApiDeploy.ts +++ b/src/client/metadataApiDeploy.ts @@ -11,6 +11,7 @@ import JSZip from 'jszip'; import fs from 'graceful-fs'; import { Lifecycle, Messages, SfError } from '@salesforce/core'; import { ensureArray } from '@salesforce/kit'; +import { posixify } from '../utils/path'; import { RegistryAccess } from '../registry/registryAccess'; import { ReplacementEvent } from '../convert/types'; import { MetadataConverter } from '../convert/metadataConverter'; @@ -311,8 +312,7 @@ export class MetadataApiDeploy extends MetadataTransfer< // Add relative file paths to a root of "zip" for MDAPI. const relPath = join('zip', relative(mdapiPath, fullPath)); // Ensure only posix paths are added to zip files - const relPosixPath = relPath.replace(/\\/g, '/'); - zip.file(relPosixPath, fs.createReadStream(fullPath)); + zip.file(posixify(relPath), fs.createReadStream(fullPath)); } } }; diff --git a/src/convert/replacements.ts b/src/convert/replacements.ts index cba3f2e23e..60f3f9656c 100644 --- a/src/convert/replacements.ts +++ b/src/convert/replacements.ts @@ -6,11 +6,12 @@ */ import { readFile } from 'node:fs/promises'; import { Transform, Readable } from 'node:stream'; -import { sep, posix, join, isAbsolute } from 'node:path'; +import { join, isAbsolute } from 'node:path'; import { Lifecycle, Messages, SfError, SfProject } from '@salesforce/core'; import { minimatch } from 'minimatch'; import { Env } from '@salesforce/kit'; import { ensureString, isString } from '@salesforce/ts-types'; +import { posixify } from '../utils/path'; import { SourcePath } from '../common/types'; import { SourceComponent } from '../resolve/sourceComponent'; import { MarkedReplacement, ReplacementConfig, ReplacementEvent } from './types'; @@ -199,7 +200,7 @@ export const matchesFile = (r: ReplacementConfig): boolean => // filenames will be absolute. We don't have convenient access to the pkgDirs, // so we need to be more open than an exact match - (typeof r.filename === 'string' && posixifyPaths(filename).endsWith(r.filename)) || + (typeof r.filename === 'string' && posixify(filename).endsWith(r.filename)) || (typeof r.glob === 'string' && minimatch(filename, `**/${r.glob}`)); /** @@ -245,8 +246,6 @@ export const stringToRegex = (input: string): RegExp => // eslint-disable-next-line no-useless-escape new RegExp(input.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'g'); -export const posixifyPaths = (f: string): string => f.split(sep).join(posix.sep); - /** if replaceWithFile is present, resolve it to an absolute path relative to the projectdir */ const makeAbsolute = (projectDir: string) => diff --git a/src/convert/streams.ts b/src/convert/streams.ts index 5fc18e1719..7463eb58e2 100644 --- a/src/convert/streams.ts +++ b/src/convert/streams.ts @@ -13,6 +13,7 @@ import { createWriteStream, existsSync, promises as fsPromises } from 'graceful- import { JsonMap } from '@salesforce/ts-types'; import { XMLBuilder } from 'fast-xml-parser'; import { Logger } from '@salesforce/core'; +import { posixify } from '../utils/path'; import { SourceComponent } from '../resolve/sourceComponent'; import { SourcePath } from '../common/types'; import { XML_COMMENT_PROP_NAME, XML_DECL } from '../common/constants'; @@ -234,8 +235,7 @@ export class ZipWriter extends ComponentWriter { public addToZip(contents: string | Readable | Buffer, path: SourcePath): void { // Ensure only posix paths are added to zip files - const posixPath = path.replace(/\\/g, '/'); - this.zip.file(posixPath, contents); + this.zip.file(posixify(path), contents); } } diff --git a/src/convert/transformers/staticResourceMetadataTransformer.ts b/src/convert/transformers/staticResourceMetadataTransformer.ts index 668a1eeb70..07a449ff16 100644 --- a/src/convert/transformers/staticResourceMetadataTransformer.ts +++ b/src/convert/transformers/staticResourceMetadataTransformer.ts @@ -12,7 +12,7 @@ import { JsonMap } from '@salesforce/ts-types'; import { createWriteStream } from 'graceful-fs'; import { Logger, Messages, SfError } from '@salesforce/core'; import { isEmpty } from '@salesforce/kit'; -import { baseName } from '../../utils/path'; +import { baseName, posixify } from '../../utils/path'; import { WriteInfo } from '../types'; import { SourceComponent } from '../../resolve/sourceComponent'; import { SourcePath } from '../../common/types'; @@ -59,8 +59,7 @@ export class StaticResourceMetadataTransformer extends BaseMetadataTransformer { // have to walk the component content. Replacements only happen if set on the component. for (const path of component.walkContent()) { const replacementStream = getReplacementStreamForReadable(component, path); - const relPath = relative(content, path); - const relPosixPath = relPath.replace(/\\/g, '/'); + const relPosixPath = posixify(relative(content, path)); zip.file(relPosixPath, replacementStream); } diff --git a/src/utils/path.ts b/src/utils/path.ts index 69312c130d..54fd2c5dae 100644 --- a/src/utils/path.ts +++ b/src/utils/path.ts @@ -6,6 +6,7 @@ */ import { basename, dirname, extname, sep, join } from 'node:path'; +import { posix } from 'node:path/posix'; import { Optional } from '@salesforce/ts-types'; import { SfdxFileFormat } from '../convert/types'; import { SourcePath } from '../common/types'; @@ -161,3 +162,5 @@ export const fnJoin = (a: string) => (b: string): string => join(a, b); + +export const posixify = (f: string): string => f.split(sep).join(posix.sep); diff --git a/test/convert/replacements.test.ts b/test/convert/replacements.test.ts index ceb7d0328f..511809ceef 100644 --- a/test/convert/replacements.test.ts +++ b/test/convert/replacements.test.ts @@ -13,11 +13,11 @@ import { matchesFile, replacementIterations, stringToRegex, - posixifyPaths, envFilter, } from '../../src/convert/replacements'; import { matchingContentFile } from '../mock'; import * as replacementsForMock from '../../src/convert/replacements'; +import { posixify } from '../../src/utils/path'; config.truncateThreshold = 0; @@ -155,7 +155,7 @@ describe('marking replacements on a component', () => { assert(cmp.xml); const result = await getReplacements(cmp, [ // spec says filename path should be posix. The mocks are using join, so on windows they are wrong - { filename: posixifyPaths(cmp.xml), stringToReplace: 'foo', replaceWithEnv: 'FOO_REPLACEMENT' }, + { filename: posixify(cmp.xml), stringToReplace: 'foo', replaceWithEnv: 'FOO_REPLACEMENT' }, ]); expect(result).to.deep.equal({ [cmp.xml]: [ @@ -171,7 +171,7 @@ describe('marking replacements on a component', () => { it('marks string replacements from file', async () => { assert(cmp.xml); const result = await getReplacements(cmp, [ - { filename: posixifyPaths(cmp.xml), stringToReplace: 'foo', replaceWithFile: 'bar' }, + { filename: posixify(cmp.xml), stringToReplace: 'foo', replaceWithFile: 'bar' }, ]); expect(result).to.deep.equal({ [cmp.xml]: [ @@ -188,7 +188,7 @@ describe('marking replacements on a component', () => { it('marks regex replacements on a matching file', async () => { assert(cmp.xml); const result = await getReplacements(cmp, [ - { filename: posixifyPaths(cmp.xml), regexToReplace: '.*foo.*', replaceWithEnv: 'FOO_REPLACEMENT' }, + { filename: posixify(cmp.xml), regexToReplace: '.*foo.*', replaceWithEnv: 'FOO_REPLACEMENT' }, ]); expect(result).to.deep.equal({ [cmp.xml]: [ @@ -204,8 +204,8 @@ describe('marking replacements on a component', () => { it('marks 2 replacements on one file', async () => { assert(cmp.xml); const result = await getReplacements(cmp, [ - { filename: posixifyPaths(cmp.xml), stringToReplace: 'foo', replaceWithEnv: 'FOO_REPLACEMENT' }, - { filename: posixifyPaths(cmp.xml), stringToReplace: 'baz', replaceWithEnv: 'FOO_REPLACEMENT' }, + { filename: posixify(cmp.xml), stringToReplace: 'foo', replaceWithEnv: 'FOO_REPLACEMENT' }, + { filename: posixify(cmp.xml), stringToReplace: 'baz', replaceWithEnv: 'FOO_REPLACEMENT' }, ]); expect(result).to.deep.equal({ [cmp.xml]: [ @@ -253,8 +253,8 @@ describe('marking replacements on a component', () => { assert(cmp.content); assert(cmp.xml); const result = await getReplacements(cmp, [ - { filename: posixifyPaths(cmp.xml), stringToReplace: 'foo', replaceWithEnv: 'FOO_REPLACEMENT' }, - { filename: posixifyPaths(cmp.content), stringToReplace: 'foo', replaceWithEnv: 'FOO_REPLACEMENT' }, + { filename: posixify(cmp.xml), stringToReplace: 'foo', replaceWithEnv: 'FOO_REPLACEMENT' }, + { filename: posixify(cmp.content), stringToReplace: 'foo', replaceWithEnv: 'FOO_REPLACEMENT' }, ]); expect(result).to.deep.equal({ [cmp.xml]: [ @@ -280,7 +280,7 @@ describe('marking replacements on a component', () => { assert(cmp.xml); try { await getReplacements(cmp, [ - { filename: posixifyPaths(cmp.xml), regexToReplace: '.*foo.*', replaceWithEnv: 'BAD_ENV' }, + { filename: posixify(cmp.xml), regexToReplace: '.*foo.*', replaceWithEnv: 'BAD_ENV' }, ]); assert.fail('should have thrown'); } catch (e) { @@ -291,7 +291,7 @@ describe('marking replacements on a component', () => { assert(cmp.xml); const result = await getReplacements(cmp, [ { - filename: posixifyPaths(cmp.xml), + filename: posixify(cmp.xml), regexToReplace: '.*foo.*', replaceWithEnv: 'BAD_ENV', allowUnsetEnvVariable: true, diff --git a/test/mock/client/index.ts b/test/mock/client/index.ts index 9a0a140a5a..dd1e84a283 100644 --- a/test/mock/client/index.ts +++ b/test/mock/client/index.ts @@ -5,15 +5,13 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ import JSZip from 'jszip'; +import { posixify } from '../../../src/utils/path'; // eslint-disable-next-line @typescript-eslint/require-await export async function createMockZip(entries: string[]): Promise { const zip = JSZip(); - for (const entry of entries) { - // Ensure only posix paths are added to zip files - const relPosixPath = entry.replace(/\\/g, '/'); - zip.file(relPosixPath, ''); - } + // Ensure only posix paths are added to zip files + entries.map((entry) => zip.file(posixify(entry), '')); return zip.generateAsync({ type: 'nodebuffer', compression: 'DEFLATE',