Преобразовать вложенный список в объект - Javascript - PullRequest
0 голосов
/ 16 мая 2019

нам нужна помощь для решения этой проблемы, никто на нашем предприятии не смог это сделать.

У нас есть такая строка:

- name
    - type
        - string
    - validation
        - required
        - minLength
            - 4
        - maxLength
            - 20
        - optionIn
            - option1
            - option2
            - option3
            - option4
- password
    - type
        - string
    - validation
        - required
        - minLength
            - 6
        - maxLength
            - 30
- date
    - type
        - date

И нам нужно сгенерироватьобъект, подобный этому:

{
   name: {
      type: 'string',
      validation: {
        required: true,
        minLength: 4,
        maxLength: 20,
        optionIn: ['option1', 'option2', 'option3', 'option4']
      }
    },
    password: {
      type: 'string',
      validation: {
        required: true,
        minLength: 6,
        maxLength: 30
      }
    },
    date: {
      type: 'date'
    }
}

Несколько вещей, которые делают это действительно сложной задачей:

Если последний вложенный элемент - только один, это делает его значением предыдущего ключа.Если последний вложенный элемент больше одного, он становится массивом, а массив является значением предыдущего ключа.

Редактировать: Спасибо @adiga за понимание, пример 'required' становится объектомсо значением true, потому что его товарищи имеют вложенный элемент

Это сложная и сложная задача, библиотеки доступны для использования, если вам нужно.

1 Ответ

2 голосов
/ 16 мая 2019

Решение, которое я придумал, состоит из двух этапов.

Сначала я parse() inputStr в промежуточную форму самым простым способом, каким я могу, в конечном итоге выглядит так:

{
    "name": {
        "type": {
            "string": null
        },
        "validation": {
            "required": null,
            "minLength": {
                "4": null
            },
            "maxLength": {
                "20": null
            },
            "optionIn": {
                "option1": null,
                "option2": null,
                "option3": null,
                "option4": null
            }
        }
    },
    "password": {
        "type": {
            "string": null
        },
        "validation": {
            "required": null,
            "minLength": {
                "6": null
            },
            "maxLength": {
                "30": null
            }
        }
    },
    "date": {
        "type": {
            "date": null
        }
    }
}

Затем я transform() этот промежуточный объект вокончательная форма.

const inputStr = 
`- name
    - type
        - string
    - validation
        - required
        - minLength
            - 4
        - maxLength
            - 20
        - optionIn
            - option1
            - option2
            - option3
            - option4
- password
    - type
        - string
    - validation
        - required
        - minLength
            - 6
        - maxLength
            - 30
- date
    - type
        - date`

let parseLimit = 1000;
function parse(lines, curIndent = 0) {
	if (parseLimit-- < 0) throw "parseLimit exhausted";
	if (lines.length === 0) return null;
	
	const obj = {};
	let parent = null;
	let descendantLines = [];
	[...lines, '>'.repeat(curIndent)].forEach(line => {
		const indents = (line.match(/>/g) || []).length;
		if (indents === curIndent) {
			if (parent) {
				obj[parent] = parse(descendantLines, curIndent + 1);
			}
			descendantLines = [];
			parent = line.replace(/>/g, '');
		} else if (indents > curIndent) {
			descendantLines.push(line);
		} else {
			throw 'indents < curIndent';
		}
	});
	
	
	return obj;
}

let transformLimit = 1000;
function transform(node) {
	if (transformLimit-- < 0) throw "transformLimit exhausted";
	
	const childKeys = Object.keys(node);
	const leafChildKeys = childKeys.filter(childKey => {
		return node[childKey] === null;
	});
	if (childKeys.length === leafChildKeys.length) {
		//all leaf children
		const values = childKeys.map(value => {
			return isNaN(value)
				? value
				: +value;
		});
		return values.length === 1
			? values[0]
			: values;
	} else { //not all leaf children	
		const newNode = {};
		
		childKeys.forEach(childKey => {
			if (leafChildKeys.includes(childKey)) {
				//true
				newNode[childKey] = true;
			} else {
				//recurs
				newNode[childKey] = transform(node[childKey]);
			}
		});
		
		return newNode;
	}
}

function solve(str) {
	const lines = str
		.split('\n')
		.map(line => line
			.replace(/    /g, '>')
			.replace('- ', '')
		);
	return transform(parse(lines));
}

console.log('input:\n', inputStr);
console.log('solution: ', solve(inputStr));
...