Skip to content

Commit c96edd1

Browse files
author
Nicolas FRANÇOIS
committed
add inline sourceMaps support
1 parent 69cb0ca commit c96edd1

File tree

12 files changed

+579
-31
lines changed

12 files changed

+579
-31
lines changed

src/Block.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ class Block
2828
*/
2929
public $parent;
3030

31+
/**
32+
* @var string;
33+
*/
34+
public $sourceName;
35+
3136
/**
3237
* @var integer
3338
*/

src/Compiler.php

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Leafo\ScssPhp\Exception\CompilerException;
1919
use Leafo\ScssPhp\Formatter\OutputBlock;
2020
use Leafo\ScssPhp\Node;
21+
use Leafo\ScssPhp\SourceMap\SourceMapGenerator;
2122
use Leafo\ScssPhp\Type;
2223
use Leafo\ScssPhp\Parser;
2324
use Leafo\ScssPhp\Util;
@@ -64,6 +65,9 @@ class Compiler
6465
const WITH_SUPPORTS = 4;
6566
const WITH_ALL = 7;
6667

68+
const SOURCE_MAP_NONE = 0;
69+
const SOURCE_MAP_INLINE = 1;
70+
6771
/**
6872
* @var array
6973
*/
@@ -120,11 +124,16 @@ class Compiler
120124
protected $encoding = null;
121125
protected $lineNumberStyle = null;
122126

127+
protected $sourceMap = self::SOURCE_MAP_NONE;
128+
protected $sourceMapOptions = [];
129+
130+
/** @var string|Formatter */
123131
protected $formatter = 'Leafo\ScssPhp\Formatter\Nested';
124132

125133
protected $rootEnv;
126134
protected $rootBlock;
127135

136+
/** @var Environment */
128137
protected $env;
129138
protected $scope;
130139
protected $storeEnv;
@@ -191,8 +200,21 @@ public function compile($code, $path = null)
191200
$this->compileRoot($tree);
192201
$this->popEnv();
193202

194-
$out = $this->formatter->format($this->scope);
203+
$sourceMapGenerator = null;
204+
if($this->sourceMap && $this->sourceMap !== self::SOURCE_MAP_NONE) {
205+
$sourceMapGenerator = new SourceMapGenerator($this->sourceMapOptions);
206+
}
207+
$out = $this->formatter->format($this->scope, $sourceMapGenerator);
208+
if($this->sourceMap && $this->sourceMap !== self::SOURCE_MAP_NONE) {
209+
$sourceMap = $sourceMapGenerator->generateJson();
210+
211+
$sourceMapUrl = null;
212+
if($this->sourceMap == self::SOURCE_MAP_INLINE) {
213+
$sourceMapUrl = sprintf('data:application/json,%s', self::encodeURIComponent($sourceMap));
214+
}
195215

216+
$out .= sprintf('/*# sourceMappingURL=%s */', $sourceMapUrl);
217+
}
196218
return $out;
197219
}
198220

@@ -274,6 +296,9 @@ protected function makeOutputBlock($type, $selectors = null)
274296
$out->parent = $this->scope;
275297
$out->selectors = $selectors;
276298
$out->depth = $this->env->depth;
299+
$out->sourceName = $this->env->block->sourceName;
300+
$out->sourceLine = $this->env->block->sourceLine;
301+
$out->sourceColumn = $this->env->block->sourceColumn;
277302

278303
return $out;
279304
}
@@ -656,6 +681,7 @@ protected function compileMedia(Block $media)
656681

657682
if ($needsWrap) {
658683
$wrapped = new Block;
684+
$wrapped->sourceName = $media->sourceName;
659685
$wrapped->sourceIndex = $media->sourceIndex;
660686
$wrapped->sourceLine = $media->sourceLine;
661687
$wrapped->sourceColumn = $media->sourceColumn;
@@ -729,6 +755,7 @@ protected function compileAtRoot(Block $block)
729755
// wrap inline selector
730756
if ($block->selector) {
731757
$wrapped = new Block;
758+
$wrapped->sourceName = $block->sourceName;
732759
$wrapped->sourceIndex = $block->sourceIndex;
733760
$wrapped->sourceLine = $block->sourceLine;
734761
$wrapped->sourceColumn = $block->sourceColumn;
@@ -785,6 +812,7 @@ private function spliceTree($envs, Block $block, $without)
785812
}
786813

787814
$b = new Block;
815+
$b->sourceName = $e->block->sourceName;
788816
$b->sourceIndex = $e->block->sourceIndex;
789817
$b->sourceLine = $e->block->sourceLine;
790818
$b->sourceColumn = $e->block->sourceColumn;
@@ -1076,6 +1104,13 @@ protected function evalSelectors($selectors)
10761104
return $selectors;
10771105
}
10781106

1107+
/**
1108+
* @param array $sourceMapOptions
1109+
*/
1110+
public function setSourceMapOptions($sourceMapOptions) {
1111+
$this->sourceMapOptions = $sourceMapOptions;
1112+
}
1113+
10791114
/**
10801115
* Evaluate selector
10811116
*
@@ -3299,6 +3334,13 @@ public function setLineNumberStyle($lineNumberStyle)
32993334
$this->lineNumberStyle = $lineNumberStyle;
33003335
}
33013336

3337+
/**
3338+
* @param int $sourceMap
3339+
*/
3340+
public function setSourceMap($sourceMap) {
3341+
$this->sourceMap = $sourceMap;
3342+
}
3343+
33023344
/**
33033345
* Register function
33043346
*
@@ -5256,4 +5298,9 @@ protected function libInspect($args)
52565298

52575299
return $args[0];
52585300
}
5301+
5302+
public static function encodeURIComponent($string){
5303+
$revert = array('%21' => '!', '%2A' => '*', '%27' => "'", '%28' => '(', '%29' => ')');
5304+
return strtr(rawurlencode($string), $revert);
5305+
}
52595306
}

src/Formatter.php

Lines changed: 69 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Leafo\ScssPhp;
1313

1414
use Leafo\ScssPhp\Formatter\OutputBlock;
15+
use Leafo\ScssPhp\SourceMap\SourceMapGenerator;
1516

1617
/**
1718
* Base formatter
@@ -56,10 +57,31 @@ abstract class Formatter
5657
public $assignSeparator;
5758

5859
/**
59-
* @var boolea
60+
* @var boolean
6061
*/
6162
public $keepSemicolons;
6263

64+
/**
65+
* @var OutputBlock;
66+
*/
67+
protected $currentBlock;
68+
69+
70+
/**
71+
* @var int
72+
*/
73+
protected $currentLine;
74+
75+
/**
76+
* @var int;
77+
*/
78+
protected $currentColumn;
79+
80+
/**
81+
* @var SourceMapGenerator
82+
*/
83+
protected $sourceMapGenerator;
84+
6385
/**
6486
* Initialize formatter
6587
*
@@ -123,10 +145,10 @@ protected function blockLines(OutputBlock $block)
123145

124146
$glue = $this->break . $inner;
125147

126-
echo $inner . implode($glue, $block->lines);
148+
$this->write($inner . implode($glue, $block->lines));
127149

128150
if (! empty($block->children)) {
129-
echo $this->break;
151+
$this->write($this->break);
130152
}
131153
}
132154

@@ -139,9 +161,9 @@ protected function blockSelectors(OutputBlock $block)
139161
{
140162
$inner = $this->indentStr();
141163

142-
echo $inner
164+
$this->write($inner
143165
. implode($this->tagSeparator, $block->selectors)
144-
. $this->open . $this->break;
166+
. $this->open . $this->break);
145167
}
146168

147169
/**
@@ -167,6 +189,8 @@ protected function block(OutputBlock $block)
167189
return;
168190
}
169191

192+
$this->currentBlock = $block;
193+
170194
$pre = $this->indentStr();
171195

172196
if (! empty($block->selectors)) {
@@ -187,10 +211,10 @@ protected function block(OutputBlock $block)
187211
$this->indentLevel--;
188212

189213
if (empty($block->children)) {
190-
echo $this->break;
214+
$this->write($this->break);
191215
}
192216

193-
echo $pre . $this->close . $this->break;
217+
$this->write($pre . $this->close . $this->break);
194218
}
195219
}
196220

@@ -201,10 +225,19 @@ protected function block(OutputBlock $block)
201225
*
202226
* @param \Leafo\ScssPhp\Formatter\OutputBlock $block An abstract syntax tree
203227
*
228+
* @param SourceMapGenerator|null $sourceMapGenerator
204229
* @return string
230+
* @internal param bool $collectSourceMap
205231
*/
206-
public function format(OutputBlock $block)
232+
public function format(OutputBlock $block, SourceMapGenerator $sourceMapGenerator = null)
207233
{
234+
if($sourceMapGenerator) {
235+
$this->currentLine = 1;
236+
$this->currentColumn = 0;
237+
$this->sourceMapGenerator = $sourceMapGenerator;
238+
} else {
239+
$this->sourceMapGenerator = null;
240+
}
208241
ob_start();
209242

210243
$this->block($block);
@@ -213,4 +246,32 @@ public function format(OutputBlock $block)
213246

214247
return $out;
215248
}
249+
250+
/**
251+
* @param $str
252+
*/
253+
protected function write($str) {
254+
if($this->sourceMapGenerator) {
255+
$this->sourceMapGenerator->addMapping(
256+
$this->currentLine,
257+
$this->currentColumn,
258+
$this->currentBlock->sourceLine,
259+
$this->currentBlock->sourceColumn,
260+
$this->currentBlock->sourceName
261+
);
262+
263+
$lines = explode("\n", $str);
264+
$lineCount = count($lines);
265+
$this->currentLine += $lineCount-1;
266+
267+
$lastLine = array_pop($lines);
268+
if($lineCount == 1) {
269+
$this->currentColumn += mb_strlen($lastLine);
270+
} else {
271+
$this->currentColumn = mb_strlen($lastLine);
272+
}
273+
}
274+
275+
echo $str;
276+
}
216277
}

src/Formatter/Compressed.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@ public function blockLines(OutputBlock $block)
5353
}
5454
}
5555

56-
echo $inner . implode($glue, $block->lines);
56+
$this->write( $inner . implode($glue, $block->lines));
5757

5858
if (! empty($block->children)) {
59-
echo $this->break;
59+
$this->write( $this->break);
6060
}
6161
}
6262
}

src/Formatter/Crunched.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@ public function blockLines(OutputBlock $block)
5151
}
5252
}
5353

54-
echo $inner . implode($glue, $block->lines);
54+
$this->write($inner . implode($glue, $block->lines));
5555

5656
if (! empty($block->children)) {
57-
echo $this->break;
57+
$this->write($this->break);
5858
}
5959
}
6060
}

src/Formatter/Debug.php

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,13 @@ protected function blockLines(OutputBlock $block)
5252
$indent = $this->indentStr();
5353

5454
if (empty($block->lines)) {
55-
echo "{$indent}block->lines: []\n";
55+
$this->write("{$indent}block->lines: []\n");
5656

5757
return;
5858
}
5959

6060
foreach ($block->lines as $index => $line) {
61-
echo "{$indent}block->lines[{$index}]: $line\n";
61+
$this->write( "{$indent}block->lines[{$index}]: $line\n");
6262
}
6363
}
6464

@@ -70,13 +70,13 @@ protected function blockSelectors(OutputBlock $block)
7070
$indent = $this->indentStr();
7171

7272
if (empty($block->selectors)) {
73-
echo "{$indent}block->selectors: []\n";
73+
$this->write( "{$indent}block->selectors: []\n");
7474

7575
return;
7676
}
7777

7878
foreach ($block->selectors as $index => $selector) {
79-
echo "{$indent}block->selectors[{$index}]: $selector\n";
79+
$this->write( "{$indent}block->selectors[{$index}]: $selector\n");
8080
}
8181
}
8282

@@ -88,7 +88,7 @@ protected function blockChildren(OutputBlock $block)
8888
$indent = $this->indentStr();
8989

9090
if (empty($block->children)) {
91-
echo "{$indent}block->children: []\n";
91+
$this->write( "{$indent}block->children: []\n");
9292

9393
return;
9494
}
@@ -109,8 +109,10 @@ protected function block(OutputBlock $block)
109109
{
110110
$indent = $this->indentStr();
111111

112-
echo "{$indent}block->type: {$block->type}\n" .
113-
"{$indent}block->depth: {$block->depth}\n";
112+
$this->write( "{$indent}block->type: {$block->type}\n" .
113+
"{$indent}block->depth: {$block->depth}\n");
114+
115+
$this->currentBlock = $block;
114116

115117
$this->blockSelectors($block);
116118
$this->blockLines($block);

src/Formatter/Expanded.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,10 @@ protected function blockLines(OutputBlock $block)
5959
}
6060
}
6161

62-
echo $inner . implode($glue, $block->lines);
62+
$this->write($inner . implode($glue, $block->lines));
6363

6464
if (empty($block->selectors) || ! empty($block->children)) {
65-
echo $this->break;
65+
$this->write($this->break);
6666
}
6767
}
6868
}

0 commit comments

Comments
 (0)