UNPKG

4.96 kBJavaScriptView Raw
1'use strict'
2Object.defineProperty(exports, '__esModule', { value: true })
3const tslib_1 = require('tslib')
4const lex_1 = require('./lex')
5class Element {
6 constructor({ pre = '\n', post = ' ' } = {}) {
7 this.pre = pre
8 this.post = post
9 }
10 get content() {
11 return `${this.pre}${this._content}${this.post}`
12 }
13}
14exports.Element = Element
15class Prop extends Element {
16 constructor(opts) {
17 super(opts)
18 this.name = opts.name
19 this.value = opts.value
20 }
21 get _content() {
22 return `${this.name} ${this.value}`
23 }
24}
25exports.Prop = Prop
26class MachineBase extends Element {
27 constructor(_a) {
28 var { props = [] } = _a,
29 opts = tslib_1.__rest(_a, ['props'])
30 super(opts)
31 this.props = props
32 }
33 get login() {
34 return this.getProp('login')
35 }
36 get password() {
37 return this.getProp('password')
38 }
39 get account() {
40 return this.getProp('account')
41 }
42 set login(v) {
43 this.setProp('login', v)
44 }
45 set password(v) {
46 this.setProp('password', v)
47 }
48 set account(v) {
49 this.setProp('account', v)
50 }
51 get content() {
52 return `${this.pre}${this._content}${this.props.map(p => p.content).join('')}${this.post}`
53 }
54 getProp(name) {
55 const p = this.props.find(p => p.name === name)
56 return p && p.value
57 }
58 setProp(name, value) {
59 if (!value) {
60 this.props = this.props.filter(p => p.name === name)
61 return
62 }
63 let p = this.props.find(p => p.name === name)
64 if (p) {
65 p.value = value
66 } else {
67 p = new Prop({ name, value })
68 this.props.push(p)
69 }
70 }
71}
72exports.MachineBase = MachineBase
73class Machine extends MachineBase {
74 constructor(_a) {
75 var { host } = _a,
76 opts = tslib_1.__rest(_a, ['host'])
77 super(opts)
78 this.type = 'machine'
79 this.host = host
80 }
81 get _content() {
82 return `machine ${this.host}`
83 }
84}
85exports.Machine = Machine
86class DefaultMachine extends MachineBase {
87 constructor() {
88 super(...arguments)
89 this.type = 'default'
90 }
91 get _content() {
92 return 'default'
93 }
94}
95exports.DefaultMachine = DefaultMachine
96function parse(body) {
97 const file = {
98 machines: {},
99 _tokens: [],
100 }
101 const tokens = lex_1.default(body)
102 const getMachineTokens = () => {
103 let machineTokens = []
104 while (tokens.length && !['machine', 'default', 'macdef'].includes(tokens[0].type)) {
105 machineTokens.push(tokens.shift())
106 }
107 return machineTokens
108 }
109 while (tokens.length) {
110 const cur = tokens.shift()
111 switch (cur.type) {
112 case 'macdef':
113 file._tokens.push(cur, ...getMachineTokens())
114 break
115 case 'default':
116 file.default = machineProxy({ type: 'default', _tokens: getMachineTokens() })
117 file._tokens.push(file.default)
118 break
119 case 'machine':
120 let host = cur.host
121 file.machines[host]._tokens = getMachineTokens()
122 break
123 default:
124 file._tokens.push(cur)
125 }
126 }
127 return file
128}
129exports.default = parse
130function machinesProxy(content) {
131 function addNewMachine(host) {
132 let machine = machineProxy({
133 type: 'machine',
134 host,
135 _tokens: [{ type: 'machine', value: host, content: `machine ${host}` }, { type: 'whitespace', content: '\n' }],
136 })
137 content.push(machine)
138 return machine
139 }
140 return new Proxy(
141 {},
142 {
143 get: (machines, host) => {
144 if (typeof host !== 'string') return machines[host]
145 if (!machines[host]) machines[host] = addNewMachine(host)
146 return machines[host]
147 },
148 set: (machines, host, value) => {
149 if (!machines[host]) machines[host] = addNewMachine(host)
150 machines[host] = machineProxy(value)
151 return true
152 },
153 deleteProperty: (machines, host) => {
154 if (!machines[host]) return false
155 delete machines[host]
156 for (let i = 0; i < content.length; i++) {
157 if (content[i].type === 'machine' && content[i].value === host) {
158 content.splice(i, 1)
159 }
160 }
161 return true
162 },
163 },
164 )
165}
166function machineProxy(machine) {
167 const props = () => machine._tokens.filter(t => t.type === 'prop')
168 const loadProps = () =>
169 props().forEach(prop => {
170 machine[prop.name] = prop.value
171 })
172 loadProps()
173 return new Proxy(machine, {
174 set: (machine, name, value) => {
175 machine[name] = value
176 let prop = props().find(p => p.name === name)
177 if (prop) prop.value = value
178 else {
179 let lastPropIdx = findIndex(machine._tokens, t => t.type === 'prop')
180 let whitespace = lastPropIdx === -1 ? { type: 'whitespace', content: '\n ' } : machine._tokens[lastPropIdx - 1]
181 machine._tokens.splice(lastPropIdx, 0, whitespace) // insert whitespace
182 machine._tokens.splice(lastPropIdx, 0, { type: 'prop', name, value })
183 }
184 return true
185 },
186 })
187}
188function findIndex(arr, fn) {
189 for (let i = 0; i < arr.length; i++) {
190 if (fn(arr[i])) return i
191 }
192 return -1
193}