-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
input.js
146 lines (122 loc) · 3.27 KB
/
input.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
'use strict'
let { fileURLToPath, pathToFileURL } = require('url')
let { resolve, isAbsolute } = require('path')
let { nanoid } = require('nanoid/non-secure')
let lineColumn = require('line-column')
let terminalHighlight = require('./terminal-highlight')
let CssSyntaxError = require('./css-syntax-error')
let PreviousMap = require('./previous-map')
class Input {
constructor (css, opts = {}) {
if (
css === null ||
typeof css === 'undefined' ||
(typeof css === 'object' && !css.toString)
) {
throw new Error(`PostCSS received ${css} instead of CSS string`)
}
this.css = css.toString()
if (this.css[0] === '\uFEFF' || this.css[0] === '\uFFFE') {
this.hasBOM = true
this.css = this.css.slice(1)
} else {
this.hasBOM = false
}
if (opts.from) {
if (/^\w+:\/\//.test(opts.from) || isAbsolute(opts.from)) {
this.file = opts.from
} else {
this.file = resolve(opts.from)
}
}
let map = new PreviousMap(this.css, opts)
if (map.text) {
this.map = map
let file = map.consumer().file
if (!this.file && file) this.file = this.mapResolve(file)
}
if (!this.file) {
this.id = '<input css ' + nanoid(6) + '>'
}
if (this.map) this.map.file = this.from
}
fromOffset (offset) {
let finder = lineColumn(this.css)
this.fromOffset = i => finder.fromIndex(i)
return this.fromOffset(offset)
}
error (message, line, column, opts = {}) {
let result
if (!column) {
let pos = this.fromOffset(line)
line = pos.line
column = pos.col
}
let origin = this.origin(line, column)
if (origin) {
result = new CssSyntaxError(
message,
origin.line,
origin.column,
origin.source,
origin.file,
opts.plugin
)
} else {
result = new CssSyntaxError(
message,
line,
column,
this.css,
this.file,
opts.plugin
)
}
result.input = { line, column, source: this.css }
if (this.file) {
result.input.url = pathToFileURL(this.file).toString()
result.input.file = this.file
}
return result
}
origin (line, column) {
if (!this.map) return false
let consumer = this.map.consumer()
let from = consumer.originalPositionFor({ line, column })
if (!from.source) return false
let fromUrl
if (isAbsolute(from.source)) {
fromUrl = pathToFileURL(from.source)
} else {
fromUrl = new URL(
from.source,
this.map.consumer().sourceRoot || pathToFileURL(this.map.mapFile)
)
}
let result = {
url: fromUrl.toString(),
line: from.line,
column: from.column
}
if (fromUrl.protocol === 'file:') {
result.file = fileURLToPath(fromUrl)
}
let source = consumer.sourceContentFor(from.source)
if (source) result.source = source
return result
}
mapResolve (file) {
if (/^\w+:\/\//.test(file)) {
return file
}
return resolve(this.map.consumer().sourceRoot || this.map.root || '.', file)
}
get from () {
return this.file || this.id
}
}
module.exports = Input
Input.default = Input
if (terminalHighlight && terminalHighlight.registerInput) {
terminalHighlight.registerInput(Input)
}