eslint-plugin-logical-properties
Version:
103 lines (102 loc) • 3.98 kB
JavaScript
import { propertyTraverseWildcard } from './propertyTraverse.constants.js';
export const pathToSegments = (path) => (path
.replaceAll(/(\w+)(\[[^\]]])/g, '$1.$2')
.split('.'));
export const segmentsToPath = (segments) => (segments.join('.'));
export const isWildcard = (input) => (input === propertyTraverseWildcard);
export const segmentsIsEmpty = (input) => (input.length === 0
|| (input.length === 1 && input[0] === ''));
function normlizePackInput(input, 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, separator = '`') {
return input
.replaceAll(`"${separator}`, `${separator}`)
.replaceAll(`${separator}"`, `${separator}`);
}
export const packer = {
unpack: (input) => {
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) => {
const stringified = JSON.stringify(input);
const normalized = normalizePackOutput(normalizePackOutput(stringified, '`'), '\'');
return normalized;
},
};
export const generateObjectStringFromPath = (input, insert) => {
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 = { [current]: next };
return packer.pack(newObject);
};
export const generateObjectStringsFromPaths = (input, insert) => {
const paths = input.includes('')
? input
: ['', ...input];
return paths.map((path) => generateObjectStringFromPath(path, insert));
};
export const generateObjectStringTestCaseDeclaration = ({ testName, functionName }, objectString) => `const ${testName} = ${functionName}(${objectString})`;
export const generateObjectStringTestCases = ({ resolvers, ...declarationOptions }, { input, output, }) => {
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 = [];
for (const [index, code] of Object.entries(inputObjectStrings)) {
result.push({
code,
output: outputObjectStrings[index],
});
}
return result;
};