| 'use strict'
|
|
|
| let AtRule = require('./at-rule')
|
| let Comment = require('./comment')
|
| let Declaration = require('./declaration')
|
| let Input = require('./input')
|
| let PreviousMap = require('./previous-map')
|
| let Root = require('./root')
|
| let Rule = require('./rule')
|
|
|
| function hydrateInputs(json, inputs) {
|
| if (!json.inputs) return inputs
|
| return json.inputs.map(input => {
|
| let inputHydrated = { ...input, __proto__: Input.prototype }
|
| if (inputHydrated.map) {
|
| inputHydrated.map = {
|
| ...inputHydrated.map,
|
| __proto__: PreviousMap.prototype
|
| }
|
| }
|
| return inputHydrated
|
| })
|
| }
|
|
|
| function constructNode(json, inputs, children) {
|
| let defaults = { ...json }
|
| delete defaults.inputs
|
| delete defaults.nodes
|
| if (defaults.source) {
|
| let { inputId, ...source } = defaults.source
|
| defaults.source = source
|
| if (inputId != null) {
|
| defaults.source.input = inputs[inputId]
|
| }
|
| }
|
|
|
| let node
|
| if (defaults.type === 'root') {
|
| node = new Root(defaults)
|
| } else if (defaults.type === 'decl') {
|
| node = new Declaration(defaults)
|
| } else if (defaults.type === 'rule') {
|
| node = new Rule(defaults)
|
| } else if (defaults.type === 'comment') {
|
| node = new Comment(defaults)
|
| } else if (defaults.type === 'atrule') {
|
| node = new AtRule(defaults)
|
| } else {
|
| throw new Error('Unknown node type: ' + json.type)
|
| }
|
|
|
|
|
|
|
|
|
| if (children) {
|
| node.nodes = children
|
| for (let child of children) child.parent = node
|
| }
|
|
|
| return node
|
| }
|
|
|
| function fromJSON(json, inputs) {
|
| if (Array.isArray(json)) return json.map(n => fromJSON(n))
|
|
|
|
|
|
|
|
|
| let result
|
| let stack = [
|
| { childIndex: 0, children: [], inputs: hydrateInputs(json, inputs), json }
|
| ]
|
|
|
| while (stack.length > 0) {
|
| let frame = stack[stack.length - 1]
|
| let jsonNodes = frame.json.nodes
|
|
|
| if (jsonNodes && frame.childIndex < jsonNodes.length) {
|
| let childJson = jsonNodes[frame.childIndex]
|
| frame.childIndex += 1
|
| stack.push({
|
| childIndex: 0,
|
| children: [],
|
| inputs: hydrateInputs(childJson, frame.inputs),
|
| json: childJson
|
| })
|
| continue
|
| }
|
|
|
| stack.pop()
|
| let node = constructNode(
|
| frame.json,
|
| frame.inputs,
|
| jsonNodes ? frame.children : undefined
|
| )
|
| if (stack.length > 0) {
|
| stack[stack.length - 1].children.push(node)
|
| } else {
|
| result = node
|
| }
|
| }
|
|
|
| return result
|
| }
|
|
|
| module.exports = fromJSON
|
| fromJSON.default = fromJSON
|
|
|