1package sourcemap
2
3import (
4	"errors"
5	"io"
6	"strings"
7
8	"github.com/go-sourcemap/sourcemap/internal/base64vlq"
9)
10
11type fn func(m *mappings) (fn, error)
12
13type mapping struct {
14	genLine      int32
15	genColumn    int32
16	sourcesInd   int32
17	sourceLine   int32
18	sourceColumn int32
19	namesInd     int32
20}
21
22type mappings struct {
23	rd  *strings.Reader
24	dec base64vlq.Decoder
25
26	hasName bool
27	value   mapping
28
29	values []mapping
30}
31
32func parseMappings(s string) ([]mapping, error) {
33	if s == "" {
34		return nil, errors.New("sourcemap: mappings are empty")
35	}
36
37	rd := strings.NewReader(s)
38	m := &mappings{
39		rd:  rd,
40		dec: base64vlq.NewDecoder(rd),
41
42		values: make([]mapping, 0, mappingsNumber(s)),
43	}
44	m.value.genLine = 1
45	m.value.sourceLine = 1
46
47	err := m.parse()
48	if err != nil {
49		return nil, err
50	}
51
52	values := m.values
53	m.values = nil
54	return values, nil
55}
56
57func mappingsNumber(s string) int {
58	return strings.Count(s, ",") + strings.Count(s, ";")
59}
60
61func (m *mappings) parse() error {
62	next := parseGenCol
63	for {
64		c, err := m.rd.ReadByte()
65		if err == io.EOF {
66			m.pushValue()
67			return nil
68		}
69		if err != nil {
70			return err
71		}
72
73		switch c {
74		case ',':
75			m.pushValue()
76			next = parseGenCol
77		case ';':
78			m.pushValue()
79
80			m.value.genLine++
81			m.value.genColumn = 0
82
83			next = parseGenCol
84		default:
85			err := m.rd.UnreadByte()
86			if err != nil {
87				return err
88			}
89
90			next, err = next(m)
91			if err != nil {
92				return err
93			}
94		}
95	}
96}
97
98func parseGenCol(m *mappings) (fn, error) {
99	n, err := m.dec.Decode()
100	if err != nil {
101		return nil, err
102	}
103	m.value.genColumn += n
104	return parseSourcesInd, nil
105}
106
107func parseSourcesInd(m *mappings) (fn, error) {
108	n, err := m.dec.Decode()
109	if err != nil {
110		return nil, err
111	}
112	m.value.sourcesInd += n
113	return parseSourceLine, nil
114}
115
116func parseSourceLine(m *mappings) (fn, error) {
117	n, err := m.dec.Decode()
118	if err != nil {
119		return nil, err
120	}
121	m.value.sourceLine += n
122	return parseSourceCol, nil
123}
124
125func parseSourceCol(m *mappings) (fn, error) {
126	n, err := m.dec.Decode()
127	if err != nil {
128		return nil, err
129	}
130	m.value.sourceColumn += n
131	return parseNamesInd, nil
132}
133
134func parseNamesInd(m *mappings) (fn, error) {
135	n, err := m.dec.Decode()
136	if err != nil {
137		return nil, err
138	}
139	m.hasName = true
140	m.value.namesInd += n
141	return parseGenCol, nil
142}
143
144func (m *mappings) pushValue() {
145	if m.value.sourceLine == 1 && m.value.sourceColumn == 0 {
146		return
147	}
148
149	if m.hasName {
150		m.values = append(m.values, m.value)
151		m.hasName = false
152	} else {
153		m.values = append(m.values, mapping{
154			genLine:      m.value.genLine,
155			genColumn:    m.value.genColumn,
156			sourcesInd:   m.value.sourcesInd,
157			sourceLine:   m.value.sourceLine,
158			sourceColumn: m.value.sourceColumn,
159			namesInd:     -1,
160		})
161	}
162}
163