Skip to content
This repository was archived by the owner on Oct 24, 2025. It is now read-only.

Commit 85fbc05

Browse files
committed
Update libsass to 3.2.0-beta.4
1 parent 963996a commit 85fbc05

File tree

7 files changed

+206
-51
lines changed

7 files changed

+206
-51
lines changed

lib/CSS/Sass.pm

Lines changed: 73 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ require XSLoader;
5656
XSLoader::load('CSS::Sass', $VERSION);
5757
require CSS::Sass::Type;
5858

59-
sub new {
59+
sub new
60+
{
6061
my ($class, %options) = @_;
6162
# Ensure initial sub structures on options
6263
$options{plugin_paths} = [] unless exists $options{plugin_paths};
@@ -66,64 +67,100 @@ sub new {
6667
bless { options => \%options }, $class;
6768
};
6869

69-
sub options {
70+
sub options
71+
{
7072
shift->{options}
7173
}
7274

73-
sub last_error {
75+
sub last_error
76+
{
7477
my ($self) = @_;
7578
$self->{last_error}
7679
}
7780

78-
sub sass_compile {
81+
my @path_types = (
82+
'plugin_paths',
83+
'include_paths'
84+
);
85+
86+
# directory delimiter according to platform
87+
my $dir_delim = $^O eq 'MSWin32' ? ';' : ':';
88+
89+
# normalize option hash
90+
my $normalize_options = sub
91+
{
92+
my ($options) = @_;
93+
# gather all functions
94+
# they need to be hashes
95+
my %functions =
96+
(
97+
%{$options->{'functions'} || {}},
98+
%{$options->{'sass_functions'} || {}}
99+
);
100+
# create functions array
101+
# help the c code a little
102+
my @functions = map { [
103+
$_, $functions{$_}
104+
] } keys %functions;
105+
# gather all importers
106+
# they need to be arrays
107+
my @importers =
108+
map {
109+
ref($_) eq "ARRAY" ?
110+
$_ : [ $_, 0 ];
111+
}
112+
grep { defined }
113+
(
114+
$options->{'importer'},
115+
@{$options->{'importers'} || []},
116+
@{$options->{'sass_importers'} || []}
117+
);
118+
# gather all paths strings
119+
foreach my $type (@path_types)
120+
{
121+
$options->{$type} = join $dir_delim,
122+
map { split $dir_delim, $_ }
123+
@{$options->{$type} || []};
124+
}
125+
# now normalize the original hash
126+
$options->{'functions'} = \@functions;
127+
$options->{'importers'} = \@importers;
128+
# remove importer from options
129+
# it is now included in importers
130+
delete $options->{'importer'};
131+
# return pointer
132+
return $options;
133+
};
134+
135+
sub sass_compile
136+
{
79137
my ($sass_code, %options) = @_;
80138
no warnings 'uninitialized';
81-
my $r = compile_sass($sass_code, { %options,
82-
# Override sass_functions with the arrayref of arrayrefs that the XS expects.
83-
!$options{sass_functions} ? ()
84-
: (sass_functions => [ map { [ $_ => $options{sass_functions}->{$_} ]
85-
} keys %{$options{sass_functions}} ]),
86-
# Override include_paths with a ':' separated list
87-
!$options{include_paths} ? ()
88-
: (include_paths => join($^O eq 'MSWin32' ? ';' : ':',
89-
@{$options{include_paths}})),
90-
# Override plugin_paths with a ':' separated list
91-
!$options{plugin_paths} ? ()
92-
: (plugin_paths => join($^O eq 'MSWin32' ? ';' : ':',
93-
@{$options{plugin_paths}})),
94-
});
139+
$normalize_options->(\%options);
140+
my $r = compile_sass($sass_code, \%options);
95141
wantarray ? ($r->{output_string}, $r->{error_message}, $r) : $r->{output_string}
96142
}
97143

98-
sub sass_compile_file {
144+
sub sass_compile_file
145+
{
99146
my ($input_path, %options) = @_;
100147
no warnings 'uninitialized';
101-
my $r = compile_sass_file($input_path, { %options,
102-
# Override sass_functions with the arrayref of arrayrefs that the XS expects.
103-
!$options{sass_functions} ? ()
104-
: (sass_functions => [ map { [ $_ => $options{sass_functions}->{$_} ]
105-
} keys %{$options{sass_functions}} ]),
106-
# Override include_paths with a ':' separated list
107-
!$options{include_paths} ? ()
108-
: (include_paths => join($^O eq 'MSWin32' ? ';' : ':',
109-
@{$options{include_paths}})),
110-
# Override plugin_paths with a ':' separated list
111-
!$options{plugin_paths} ? ()
112-
: (plugin_paths => join($^O eq 'MSWin32' ? ';' : ':',
113-
@{$options{plugin_paths}})),
114-
});
148+
$normalize_options->(\%options);
149+
my $r = compile_sass_file($input_path, \%options);
115150
wantarray ? ($r->{output_string}, $r->{error_message}, $r) : $r->{output_string}
116151
}
117152

118-
sub compile {
153+
sub compile
154+
{
119155
my ($self, $sass_code) = @_;
120156
my ($compiled, $stats);
121157
($compiled, $self->{last_error}, $stats) = sass_compile($sass_code, %{$self->options});
122158
croak $self->{last_error} if $self->{last_error} && !$self->options->{dont_die};
123159
wantarray ? ($compiled, $stats) : $compiled
124160
}
125161

126-
sub compile_file {
162+
sub compile_file
163+
{
127164
my ($self, $sass_file) = @_;
128165
my ($compiled, $stats);
129166
($compiled, $self->{last_error}, $stats) = sass_compile_file($sass_file, %{$self->options});
@@ -494,7 +531,7 @@ L<The CSS::Sass Home Page|https://github.com/sass/perl-libsass>
494531
495532
=head1 AUTHOR
496533
497-
David Caldwell E<lt>david@porkrind.orgE<gt>
534+
David Caldwell E<lt>david@porkrind.orgE<gt>
498535
Marcel Greter E<lt>perl-libsass@ocbnet.chE<gt>
499536
500537
=head1 LICENSE

lib/CSS/Sass.xs

Lines changed: 95 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,11 @@
1414

1515
#include "ppport.h"
1616

17+
#include "sass.h"
1718
#include "sass2scss.h"
19+
#include "sass_values.h"
1820
#include "sass_context.h"
21+
#include "sass_functions.h"
1922

2023
#define isSafeSv(sv) sv && SvOK(*sv)
2124
#define Constant(c) newCONSTSUB(stash, #c, newSViv(c))
@@ -293,7 +296,7 @@ SV* sass_value_to_sv(union Sass_Value* val)
293296
}
294297

295298

296-
struct Sass_Import** sass_importer(const char* url, const char* prev, void* cookie)
299+
Sass_Import_List sass_importer(const char* cur_path, Sass_Importer_Entry cb, struct Sass_Compiler* comp)
297300
{
298301

299302
dSP;
@@ -305,9 +308,13 @@ struct Sass_Import** sass_importer(const char* url, const char* prev, void* cook
305308
ENTER;
306309
SAVETMPS;
307310

311+
void* cookie = sass_importer_get_cookie(cb);
312+
struct Sass_Import* previous = sass_compiler_get_last_import(comp);
313+
const char* prev_path = sass_import_get_path(previous);
314+
308315
PUSHMARK(SP);
309-
XPUSHs(sv_2mortal(newSVpv(url, 0)));
310-
XPUSHs(sv_2mortal(newSVpv(prev, 0)));
316+
XPUSHs(sv_2mortal(newSVpv(cur_path, 0)));
317+
XPUSHs(sv_2mortal(newSVpv(prev_path, 0)));
311318
PUTBACK;
312319

313320
// call the static function by soft name reference
@@ -439,9 +446,8 @@ struct Sass_Import** sass_importer(const char* url, const char* prev, void* cook
439446

440447
}
441448

442-
443449
// we are called by libsass to dispatch to registered functions
444-
union Sass_Value* call_sass_function(const union Sass_Value* s_args, void* cookie)
450+
union Sass_Value* call_sass_function(const union Sass_Value* s_args, Sass_Function_Entry cb, struct Sass_Options* opts)
445451
{
446452

447453
dSP;
@@ -454,6 +460,8 @@ union Sass_Value* call_sass_function(const union Sass_Value* s_args, void* cooki
454460
ENTER;
455461
SAVETMPS;
456462

463+
void* cookie = sass_function_get_cookie(cb);
464+
457465
PUSHMARK(SP);
458466
for (i=0; i<sass_list_get_length(s_args); i++) {
459467
// get the Sass_Value from libsass
@@ -518,8 +526,9 @@ SV* init_sass_options(struct Sass_Options* sass_options, HV* perl_options)
518526
SV** indent_sv = hv_fetchs(perl_options, "indent", false);
519527
SV** source_map_root_sv = hv_fetchs(perl_options, "source_map_root", false);
520528
SV** source_map_file_sv = hv_fetchs(perl_options, "source_map_file", false);
521-
SV** sass_functions_sv = hv_fetchs(perl_options, "sass_functions", false);
522-
SV** importer_sv = hv_fetchs(perl_options, "importer", false);
529+
SV** sass_headers_sv = hv_fetchs(perl_options, "headers", false);
530+
SV** sass_importers_sv = hv_fetchs(perl_options, "importers", false);
531+
SV** sass_functions_sv = hv_fetchs(perl_options, "functions", false);
523532

524533
if (input_path_sv) sass_option_set_input_path (sass_options, safe_svpv(*input_path_sv, ""));
525534
if (output_path_sv) sass_option_set_output_path (sass_options, safe_svpv(*output_path_sv, ""));
@@ -539,7 +548,67 @@ SV* init_sass_options(struct Sass_Options* sass_options, HV* perl_options)
539548
if (isSafeSv(linefeed_sv)) sass_option_set_linefeed (sass_options, SvPV_nolen(*linefeed_sv));
540549
if (isSafeSv(precision_sv)) sass_option_set_precision (sass_options, SvUV(*precision_sv));
541550

542-
if (importer_sv) { sass_option_set_importer(sass_options, sass_make_importer(sass_importer, *importer_sv)); }
551+
if (sass_importers_sv) {
552+
int i;
553+
AV* sass_importers_av;
554+
if (!SvROK(*sass_importers_sv) || SvTYPE(SvRV(*sass_importers_sv)) != SVt_PVAV) {
555+
return newSVpvf("sass_importers should be an arrayref (SvTYPE=%u)", (unsigned)SvTYPE(SvRV(*sass_importers_sv)));
556+
}
557+
sass_importers_av = (AV*)SvRV(*sass_importers_sv);
558+
559+
Sass_Importer_List c_importers = sass_make_importer_list(av_len(sass_importers_av) + 1);
560+
561+
if (!c_importers) {
562+
return newSVpv("couldn't alloc memory for c_importers", 0);
563+
}
564+
for (i=0; i<=av_len(sass_importers_av); i++) {
565+
SV** entry_sv = av_fetch(sass_importers_av, i, false);
566+
AV* entry_av;
567+
if (!SvROK(*entry_sv) || SvTYPE(SvRV(*entry_sv)) != SVt_PVAV) {
568+
return newSVpvf("each sass_importer entry should be an arrayref (SvTYPE=%u)", (unsigned)SvTYPE(SvRV(*entry_sv)));
569+
}
570+
entry_av = (AV*)SvRV(*entry_sv);
571+
572+
SV** importer_sv = av_fetch(entry_av, 0, false);
573+
SV** priority_sv = av_fetch(entry_av, 1, false);
574+
double priority = priority_sv ? SvNV(*priority_sv) : 0;
575+
if (!importer_sv) return newSVpv("custom importer without callback", 0);
576+
c_importers[i] = sass_make_importer(sass_importer, priority, *importer_sv);
577+
}
578+
579+
sass_option_set_c_importers(sass_options, c_importers);
580+
}
581+
582+
if (sass_headers_sv) {
583+
int i;
584+
AV* sass_headers_av;
585+
if (!SvROK(*sass_headers_sv) || SvTYPE(SvRV(*sass_headers_sv)) != SVt_PVAV) {
586+
return newSVpvf("sass_headers should be an arrayref (SvTYPE=%u)", (unsigned)SvTYPE(SvRV(*sass_headers_sv)));
587+
}
588+
sass_headers_av = (AV*)SvRV(*sass_headers_sv);
589+
590+
Sass_Importer_List c_headers = sass_make_importer_list(av_len(sass_headers_av) + 1);
591+
592+
if (!c_headers) {
593+
return newSVpv("couldn't alloc memory for c_headers", 0);
594+
}
595+
for (i=0; i<=av_len(sass_headers_av); i++) {
596+
SV** entry_sv = av_fetch(sass_headers_av, i, false);
597+
AV* entry_av;
598+
if (!SvROK(*entry_sv) || SvTYPE(SvRV(*entry_sv)) != SVt_PVAV) {
599+
return newSVpvf("each sass_header entry should be an arrayref (SvTYPE=%u)", (unsigned)SvTYPE(SvRV(*entry_sv)));
600+
}
601+
entry_av = (AV*)SvRV(*entry_sv);
602+
603+
SV** header_sv = av_fetch(entry_av, 0, false);
604+
SV** priority_sv = av_fetch(entry_av, 1, false);
605+
double priority = priority_sv ? SvNV(*priority_sv) : 0;
606+
if (!header_sv) return newSVpv("custom header without callback", 0);
607+
c_headers[i] = sass_make_importer(sass_importer, priority, *header_sv);
608+
}
609+
610+
sass_option_set_c_headers(sass_options, c_headers);
611+
}
543612

544613
if (sass_functions_sv) {
545614
int i;
@@ -549,7 +618,7 @@ SV* init_sass_options(struct Sass_Options* sass_options, HV* perl_options)
549618
}
550619
sass_functions_av = (AV*)SvRV(*sass_functions_sv);
551620

552-
Sass_C_Function_List c_functions = sass_make_function_list(av_len(sass_functions_av) + 1);
621+
Sass_Function_List c_functions = sass_make_function_list(av_len(sass_functions_av) + 1);
553622

554623
if (!c_functions) {
555624
return newSVpv("couldn't alloc memory for c_functions", 0);
@@ -749,6 +818,23 @@ unquote(str)
749818
OUTPUT:
750819
RETVAL
751820

821+
SV*
822+
resolve_file(file)
823+
char* file
824+
CODE:
825+
{
826+
827+
const char* paths[4] = { ".", "t", "bin", NULL };
828+
char* resolved = sass_resolve_file(file, paths);
829+
830+
RETVAL = newSVpv(resolved, 0);
831+
832+
free (resolved);
833+
834+
}
835+
OUTPUT:
836+
RETVAL
837+
752838
SV*
753839
import_sv(sv)
754840
SV* sv

t/01_xs.t

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ is ($r->{error_status}, 0, "import no error_status");
9393
is ($r->{error_message}, undef, "import error_message is undef");
9494
like ($r->{output_string}, qr/0\.33333;/, "default float precision is 5");
9595

96-
# has regression in https://github.com/sass/libsass/issues/364
9796
$r = CSS::Sass::compile_sass('.valid { width: #{(1/3)}; }', { precision => 10 });
9897
is ($r->{error_status}, 0, "import no error_status");
9998
is ($r->{error_message}, undef, "import error_message is undef");

t/02_perl.t

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use strict;
44
use warnings;
55

6-
use Test::More tests => 39;
6+
use Test::More tests => 41;
77
BEGIN { use_ok('CSS::Sass', qw(:DEFAULT sass_compile sass_compile_file)) };
88

99
my $r;
@@ -183,3 +183,12 @@ is ($err, undef, "custom precision works without error")
183183
like ($r, qr/padding\:0.3333333333\W/, "custom precision has correct output");
184184

185185
close($fh);
186+
187+
# test quote and unquote helpers
188+
my $quoted = CSS::Sass::quote("hello world");
189+
is ($quoted, "\"hello world\"", "test quote");
190+
my $unquoted = CSS::Sass::unquote($quoted);
191+
is ($unquoted, "hello world", "test unquote");
192+
193+
# test file resolve helper
194+
# die " hello [", CSS::Sass::resolve_file("bin/psass.pl"), "]";

0 commit comments

Comments
 (0)