UNPKG

eslint-plugin-logical-properties

Version:
173 lines (153 loc) 4.5 kB
import { propertyTraverseWildcard } from './propertyTraverse.constants.js'; export const pathToSegments = (path: string) => ( path .replaceAll(/(\w+)(\[[^\]]])/g, '$1.$2') .split('.') ); export const segmentsToPath = (segments: string[]) => ( segments.join('.') ); export const isWildcard = (input: string) => ( input === propertyTraverseWildcard ); export const segmentsIsEmpty = (input: string[]) => ( input.length === 0 || (input.length === 1 && input[0] === '') ); function normlizePackInput(input: string, separator = '`') { const segments = [...input]; let nextIndex = segments.indexOf(separator); let open = true; if (nextIndex < 0) { return input; } do { if (open) { segments.splice(nextIndex, 1, `"${separator}`); open = false; } else { segments.splice(nextIndex, 1, `${separator}"`); open = true; } nextIndex = segments.indexOf(separator, nextIndex + 2); } while (nextIndex >= 0); return segments.join(''); } function normalizePackOutput(input: string, separator = '`') { return input .replaceAll(`"${separator}`, `${separator}`) .replaceAll(`${separator}"`, `${separator}`); } export const packer = { unpack: (input: string) => { const normalized = normlizePackInput( normlizePackInput(input, '`'), '\'', ) .replaceAll(/":\s*([\d.A-Za-z-]+)\s*/g, '":"$1"') .replaceAll(/":\s*\${([\d.A-Za-z-]+)\s*}/g, '":"$1"'); try { const parsed = JSON.parse(normalized); return parsed; } catch { throw new Error(JSON.stringify({ input, normalized, }, undefined, 2)); } }, pack: (input: unknown) => { const stringified = JSON.stringify(input); const normalized = normalizePackOutput( normalizePackOutput(stringified, '`'), '\'', ); return normalized; }, }; export const generateObjectStringFromPath = ( input: string | string[], insert: string, ) => { const segments = Array.isArray(input) ? input : pathToSegments(input); if (segmentsIsEmpty(segments)) { return insert; } const [current, ...nextSegments] = segments; const nextString = generateObjectStringFromPath(nextSegments, insert); const next = packer.unpack(nextString); const maybeAccessor = current.match(/^\[(\d+)]$/); if (maybeAccessor) { const [,match] = maybeAccessor; const index = Number.parseInt(match, 10)!; const newArray = Array.from({ length: index + 2 }); newArray[index] = next; return packer.pack(newArray); } const newObject: Record<string, unknown> = { [current]: next }; return packer.pack(newObject); }; export const generateObjectStringsFromPaths = ( input: string[] | readonly string[], insert: string, ) => { const paths = input.includes('') ? input : ['', ...input]; return paths.map((path) => generateObjectStringFromPath(path, insert)); }; export type ObjectStringTestCaseDeclaration = { testName: string, functionName: string, }; export const generateObjectStringTestCaseDeclaration = ( { testName, functionName }: ObjectStringTestCaseDeclaration, objectString: string, ) => `const ${testName} = ${functionName}(${objectString})`; export type ObjectStringTestCaseOptions = ( & ObjectStringTestCaseDeclaration & { resolvers: string[] | readonly string[] } ); export type ObjectStringTestCase = { input: Record<string, unknown> | string, output?: Record<string, unknown> | string, }; export const generateObjectStringTestCases = ( { resolvers, ...declarationOptions }: ObjectStringTestCaseOptions, { input, output, }: ObjectStringTestCase, ) => { const inputObject = typeof input === 'string' ? input : packer.pack(input); const outputObject = output ? (typeof output === 'string' ? output : packer.pack(output)) : undefined; const declarationGenerator = generateObjectStringTestCaseDeclaration.bind( undefined, declarationOptions, ); const inputObjectStrings = generateObjectStringsFromPaths( resolvers, inputObject, ).map(declarationGenerator); const outputObjectStrings = outputObject ? generateObjectStringsFromPaths( resolvers, outputObject, ).map(declarationGenerator) : []; const result: { code: string, output?: string }[] = []; for (const [index, code] of Object.entries(inputObjectStrings)) { result.push({ code, output: outputObjectStrings[Number(index)], }); } return result; };