Пример #1
0
func TestFuncImageURL(t *testing.T) {
	ctx := libsass.Context{
		BuildDir: "test/build",
		ImageDir: "test/img",
	}

	usv, _ := libsass.Marshal([]string{"image.png"})
	usv = ImageURL(&ctx, usv)
	var path string
	libsass.Unmarshal(usv, &path)
	if e := "url('../img/image.png')"; e != path {
		t.Errorf("got: %s wanted: %s", path, e)
	}

	// Test sending invalid date to imageURL
	usv, _ = libsass.Marshal(libsass.SassNumber{Value: 1, Unit: "px"})
	_ = usv
	errusv := ImageURL(&ctx, usv)
	var s string
	merr := libsass.Unmarshal(errusv, &s)
	if merr != nil {
		t.Error(merr)
	}

	e := "Sassvalue is type context.SassNumber and has value {1 px} but expected slice"

	if e != s {
		t.Errorf("got:\n%s\nwanted:\n%s", s, e)
	}

}
Пример #2
0
// ImageWidth takes a file path (or sprite glob) and returns the
// width in pixels of the image being referenced.
func ImageWidth(mainctx context.Context, usv libsass.SassValue) (rsv *libsass.SassValue, err error) {
	var (
		glob, name string
	)
	comp, err := libsass.CompFromCtx(mainctx)
	if err != nil {
		return
	}

	err = libsass.Unmarshal(usv, &name)
	// Check for sprite-file override first
	if err != nil {
		var inf interface{}
		var infs []interface{}
		// Can't unmarshal to []interface{}, so unmarshal to
		// interface{} then reflect it into a []interface{}
		err = libsass.Unmarshal(usv, &inf)
		k := reflect.ValueOf(&infs).Elem()
		k.Set(reflect.ValueOf(inf))

		if err != nil {
			return
		}
		glob = infs[0].(string)
		name = infs[1].(string)
	}
	paths := comp.(libsass.Pather)
	imgs := sw.New(&sw.Options{
		ImageDir:  paths.ImgDir(),
		BuildDir:  paths.BuildDir(),
		GenImgDir: paths.ImgBuildDir(),
	})

	loadctx := comp.Payload()
	var images payload.Payloader

	if len(glob) == 0 {
		images = payload.Image(loadctx)
		hit := images.Get(name)
		if hit != nil {
			imgs = hit
		} else {
			imgs.Decode(name)
			images.Set(name, imgs)
		}
	} else {
		// Glob present, look up in sprites
		sprites := payload.Sprite(loadctx)
		imgs = sprites.Get(glob)
	}
	w := imgs.SImageWidth(name)
	ww := libs.SassNumber{
		Value: float64(w),
		Unit:  "px",
	}
	res, err := libsass.Marshal(ww)
	return &res, err
}
Пример #3
0
// ImageHeight takes a file path (or sprite glob) and returns the
// height in pixels of the image being referenced.
func ImageHeight(ctx *libsass.Context, usv libsass.UnionSassValue) libsass.UnionSassValue {
	var (
		glob string
		name string
	)
	err := libsass.Unmarshal(usv, &name)
	// Check for sprite-file override first
	if err != nil {
		var inf interface{}
		var infs []interface{}
		// Can't unmarshal to []interface{}, so unmarshal to
		// interface{} then reflect it into a []interface{}
		err = libsass.Unmarshal(usv, &inf)
		k := reflect.ValueOf(&infs).Elem()
		k.Set(reflect.ValueOf(inf))

		if err != nil {
			return libsass.Error(err)
		}
		glob = infs[0].(string)
		name = infs[1].(string)
	}
	imgs := sw.ImageList{
		ImageDir:  ctx.ImageDir,
		BuildDir:  ctx.BuildDir,
		GenImgDir: ctx.GenImgDir,
	}
	if glob == "" {
		if hit, ok := ctx.Imgs.M[name]; ok {
			imgs = hit
		} else {
			imgs.Decode(name)
			imgs.Combine()
			ctx.Imgs.Lock()
			ctx.Imgs.M[name] = imgs
			ctx.Imgs.Unlock()
		}
	} else {
		ctx.Sprites.RLock()
		imgs = ctx.Sprites.M[glob]
		ctx.Sprites.RUnlock()
	}
	height := imgs.SImageHeight(name)
	Hheight := libsass.SassNumber{
		Value: float64(height),
		Unit:  "px",
	}
	res, err := libsass.Marshal(Hheight)
	if err != nil {
		fmt.Println(err)
	}
	return res
}
Пример #4
0
// Sprite returns the source and background position for an image in the
// spritesheet.
func Sprite(ctx *libsass.Context, usv libsass.UnionSassValue) libsass.UnionSassValue {
	var glob, name string
	var offsetX, offsetY libsass.SassNumber
	_, _ = offsetX, offsetY // TODO: ignore these for now
	err := libsass.Unmarshal(usv, &glob, &name, &offsetX, &offsetY)
	if err != nil {
		if strings.Contains(err.Error(), "unsupported") {
			return libsass.Error(fmt.Errorf(
				"Please specify unit for offset ie. (2px)"))
		}
		return libsass.Error(err)
	}
	ctx.Sprites.RLock()
	defer ctx.Sprites.RUnlock()
	imgs, ok := ctx.Sprites.M[glob]
	if !ok {
		keys := make([]string, 0, len(ctx.Sprites.M))
		for i := range ctx.Sprites.M {
			keys = append(keys, i)
		}

		return libsass.Error(fmt.Errorf(
			"Variable not found matching glob: %s sprite:%s", glob, name))
	}

	path, err := imgs.OutputPath()

	// FIXME: path directory can not be trusted, rebuild this from the context
	if ctx.HTTPPath == "" {
		ctxPath, _ := filepath.Rel(ctx.BuildDir, ctx.GenImgDir)
		path = filepath.Join(ctxPath, filepath.Base(path))
	} else {
		u, err := url.Parse(ctx.HTTPPath)
		if err != nil {
			return libsass.Error(err)
		}
		u.Path = filepath.Join(u.Path, "build", filepath.Base(path))
		path = u.String()
	}
	if err != nil {
		return libsass.Error(err)
	}

	if imgs.Lookup(name) == -1 {
		return libsass.Error(fmt.Errorf("image %s not found\n"+
			"   try one of these: %v", name, imgs.Paths))
	}
	// This is an odd name for what it does
	pos := imgs.GetPack(imgs.Lookup(name))

	if err != nil {
		return libsass.Error(err)
	}
	str, err := libsass.Marshal(fmt.Sprintf(`url("%s") -%dpx -%dpx`,
		path, pos.X, pos.Y))
	if err != nil {
		return libsass.Error(err)
	}
	return str
}
Пример #5
0
// InlineImage returns a base64 encoded png from the input image
func InlineImage(ctx *libsass.Context, usv libsass.UnionSassValue) libsass.UnionSassValue {
	var (
		name   string
		encode bool
		f      io.Reader
	)
	err := libsass.Unmarshal(usv, &name, &encode)
	if err != nil {
		return libsass.Error(err)
	}

	f, err = os.Open(filepath.Join(ctx.ImageDir, name))
	if err != nil {
		r, err := httpInlineImage(name)
		if err != nil {
			return libsass.Error(err)
		}
		f = r
		if r != nil {
			defer r.Close()
		}
	}

	if err != nil {
		return libsass.Error(err)
	}
	var buf bytes.Buffer

	sw.Inline(f, &buf, encode)
	res, err := libsass.Marshal(buf.String())
	if err != nil {
		return libsass.Error(err)
	}
	return res
}
Пример #6
0
func TestFuncSpriteFile(t *testing.T) {
	ctx := libsass.NewContext()
	ctx.BuildDir = "../test/build"
	ctx.GenImgDir = "../test/build/img"
	ctx.ImageDir = "../test/img"

	// Add real arguments when sass lists can be [un]marshalled
	lst := []interface{}{"*.png", "139"}
	usv, _ := libsass.Marshal(lst)
	usv = SpriteFile(ctx, usv)
	var glob, path string
	err := libsass.Unmarshal(usv, &glob, &path)
	if err != nil {
		t.Error(err)
	}

	if e := "*.png"; e != glob {
		t.Errorf("got: %s wanted: %s", e, glob)
	}

	if e := "139"; e != path {
		t.Errorf("got: %s wanted: %s", e, path)
	}

}
Пример #7
0
// WarnHandler captures Sass warnings and redirects to stdout
func WarnHandler(v interface{}, csv libsass.SassValue, rsv *libsass.SassValue) error {
	var s string
	libsass.Unmarshal(csv, &s)
	fmt.Println(color.YellowString("WARNING: " + s))
	r, _ := libsass.Marshal("")
	*rsv = r
	return nil
}
Пример #8
0
// SpriteFile proxies the sprite glob and image name through.
func SpriteFile(ctx *libsass.Context, usv libsass.UnionSassValue) libsass.UnionSassValue {
	var glob, name string
	err := libsass.Unmarshal(usv, &glob, &name)
	if err != nil {
		return libsass.Error(err)
	}
	infs := []interface{}{glob, name}
	res, err := libsass.Marshal(infs)
	return res
}
Пример #9
0
// SpriteFile proxies the sprite glob and image name through.
func SpriteFile(ctx context.Context, usv libsass.SassValue) (rsv *libsass.SassValue, err error) {
	var glob, name string
	err = libsass.Unmarshal(usv, &glob, &name)
	if err != nil {
		return nil, err
	}
	infs := []interface{}{glob, name}
	res, err := libsass.Marshal(infs)
	return &res, err
}
Пример #10
0
// SpriteMap returns a sprite from the passed glob and sprite
// parameters.
func SpriteMap(ctx *libsass.Context, usv libsass.UnionSassValue) libsass.UnionSassValue {
	var glob string
	var spacing libsass.SassNumber
	err := libsass.Unmarshal(usv, &glob, &spacing)
	if err != nil {
		return libsass.Error(err)
	}
	imgs := sw.ImageList{
		ImageDir:  ctx.ImageDir,
		BuildDir:  ctx.BuildDir,
		GenImgDir: ctx.GenImgDir,
	}
	imgs.Padding = int(spacing.Value)
	if cglob, err := strconv.Unquote(glob); err == nil {
		glob = cglob
	}

	key := glob + strconv.FormatInt(int64(spacing.Value), 10)
	// TODO: benchmark a single write lock against this
	// read lock then write lock
	ctx.Sprites.RLock()
	if _, ok := ctx.Sprites.M[key]; ok {
		ctx.Sprites.RUnlock()
		res, err := libsass.Marshal(key)
		if err != nil {
			return libsass.Error(err)
		}
		return res
	}
	ctx.Sprites.RUnlock()

	err = imgs.Decode(glob)
	if err != nil {
		return libsass.Error(err)
	}
	_, err = imgs.Combine()
	if err != nil {
		return libsass.Error(err)
	}

	_, err = imgs.Export()
	if err != nil {
		return libsass.Error(err)
	}

	res, err := libsass.Marshal(key)
	ctx.Sprites.Lock()
	ctx.Sprites.M[key] = imgs
	ctx.Sprites.Unlock()
	if err != nil {
		return libsass.Error(err)
	}

	return res
}
Пример #11
0
// SpritePosition returns the position of the image in the sprite-map.
// This is useful for passing directly to background-position
func SpritePosition(mainctx context.Context, usv libsass.SassValue) (rsv *libsass.SassValue, err error) {
	comp, err := libsass.CompFromCtx(mainctx)
	if err != nil {
		return
	}

	var glob, name string
	err = libsass.Unmarshal(usv, &glob, &name)
	if err != nil {
		return
	}

	loadctx := comp.Payload()
	if loadctx == nil {
		err = ErrPayloadNil
		return
	}

	sprites := payload.Sprite(loadctx)
	if sprites == nil {
		err = errors.New("Sprites missing")
		return
	}

	imgs := sprites.Get(glob)
	if imgs == nil {
		err = fmt.Errorf(
			"Variable not found matching glob: %s sprite:%s", glob, name)
		return
	}

	if imgs.Lookup(name) == -1 {
		err = fmt.Errorf("image %s not found\n"+
			"   try one of these: %v", name, imgs.Paths())
		return
	}

	// This is an odd name for what it does
	pos := imgs.GetPack(imgs.Lookup(name))
	if err != nil {
		return
	}

	x := libs.SassNumber{Unit: "px", Value: float64(-pos.X)}
	y := libs.SassNumber{Unit: "px", Value: float64(-pos.Y)}

	str, err := libsass.Marshal(
		[]libs.SassNumber{x, y},
	)
	return &str, err
}
Пример #12
0
// ImageURL handles calls to resolve a local image from the
// built css file path.
func ImageURL(ctx *libsass.Context, csv libsass.UnionSassValue) libsass.UnionSassValue {
	var path []string
	err := libsass.Unmarshal(csv, &path)
	// This should create and throw a sass error
	if err != nil {
		return libsass.Error(err)
	}
	url := filepath.Join(ctx.RelativeImage(), path[0])
	res, err := libsass.Marshal(fmt.Sprintf("url('%s')", url))
	if err != nil {
		return libsass.Error(err)
	}
	return res
}
Пример #13
0
// FontURL builds a relative path to the requested font file from the built CSS.
func FontURL(ctx context.Context, usv libsass.SassValue) (*libsass.SassValue, error) {

	var (
		path, format string
		csv          libsass.SassValue
		raw          bool
	)
	comp, err := libsass.CompFromCtx(ctx)
	if err != nil {
		return nil, err
	}

	err = libsass.Unmarshal(usv, &path, &raw)

	if err != nil {
		return nil, err
	}
	paths := comp.(libsass.Pather)
	fdir := paths.FontDir()
	// Enter warning
	if fdir == "." || fdir == "" {
		s := "font-url: font path not set"
		return nil, errors.New(s)
	}

	rel, err := filepath.Rel(paths.BuildDir(), fdir)
	if err != nil {
		return nil, err
	}

	if raw {
		format = "%s%s"
	} else {
		format = `url("%s%s")`
	}

	abspath := filepath.Join(fdir, path)
	qry, err := qs(comp.CacheBust(), abspath)
	if err != nil {
		return nil, err
	}
	csv, err = libsass.Marshal(fmt.Sprintf(format,
		filepath.ToSlash(filepath.Join(rel, path)),
		qry,
	))

	return &csv, err
}
Пример #14
0
// InlineImage returns a base64 encoded png from the input image
func InlineImage(mainctx context.Context, usv libsass.SassValue) (rsv *libsass.SassValue, err error) {
	var (
		name   string
		encode bool
		f      io.ReadCloser
	)
	comp, err := libsass.CompFromCtx(mainctx)
	if err != nil {
		return nil, err
	}

	err = libsass.Unmarshal(usv, &name, &encode)
	if err != nil {
		return nil, err
	}

	paths := comp.(libsass.Pather)

	// check for valid URL. If true, attempt to resolve image.
	// This is really going to slow down compilation think about
	// writing data to disk instead of inlining.
	u, err := url.Parse(name)
	if err == nil && len(u.Scheme) > 0 {
		f, err = imgResolver.Do(u.String())
	} else {
		f, err = os.Open(filepath.Join(paths.ImgDir(), name))
	}
	if err != nil {
		return nil, err
	}
	defer f.Close()

	var buf bytes.Buffer
	err = sw.Inline(f, &buf, encode)
	if err != nil {
		return nil, err
	}
	res, err := libsass.Marshal(buf.String())
	if err != nil {
		return nil, err
	}
	return &res, nil
}
Пример #15
0
func TestFuncSpriteMap(t *testing.T) {
	ctx := libsass.NewContext()
	ctx.BuildDir = "../test/build"
	ctx.GenImgDir = "../test/build/img"
	ctx.ImageDir = "../test/img"

	// Add real arguments when sass lists can be [un]marshalled
	lst := []interface{}{"*.png", libsass.SassNumber{Value: 5, Unit: "px"}}
	usv, _ := libsass.Marshal(lst)
	usv = SpriteMap(ctx, usv)
	var path string
	err := libsass.Unmarshal(usv, &path)
	if err != nil {
		t.Error(err)
	}

	if e := "*.png5"; e != path {
		t.Errorf("got: %s wanted: %s", path, e)
	}
}
Пример #16
0
// ImageURL handles calls to resolve the path to a local image from the
// built css file path.
func ImageURL(ctx context.Context, csv libsass.SassValue) (*libsass.SassValue, error) {
	comp, err := libsass.CompFromCtx(ctx)
	if err != nil {
		return nil, err
	}
	pather := comp.(libsass.Pather)
	var path []string
	err = libsass.Unmarshal(csv, &path)
	// This should create and throw a sass error
	if err != nil {
		return nil, err
	}

	if len(path) != 1 {
		return nil, errors.New("path not found")
	}

	imgdir := pather.ImgDir()

	abspath := filepath.Join(imgdir, path[0])
	method := comp.CacheBust()

	qry, err := qs(method, abspath)
	if err != nil {
		return nil, err
	}
	rel, err := relativeImage(pather.BuildDir(), pather.ImgDir())
	if err != nil {
		return nil, err
	}
	url := strings.Join([]string{
		rel,
		path[0],
	}, "/")
	res, err := libsass.Marshal(fmt.Sprintf("url('%s%s')", url, qry))
	if err != nil {
		return nil, err
	}
	return &res, nil
}
Пример #17
0
func TestFuncSpriteFile(t *testing.T) {

	comp, err := libsass.New(nil, nil,
		libsass.Payload(payload.New()),
		libsass.ImgDir("../test/img"),
		libsass.BuildDir("../test/build"),
		libsass.ImgBuildDir("../test/build/img"),
	)
	if err != nil {
		t.Fatal(err)
	}

	// Add real arguments when sass lists can be [un]marshalled
	lst := []interface{}{"*.png", "139"}
	usv, err := libsass.Marshal(lst)
	if err != nil {
		t.Fatal(err)
	}

	rsv, err := SpriteFile(libsass.NewCompilerContext(comp), usv)
	if err != nil {
		t.Fatal(err)
	}
	var glob, path string
	err = libsass.Unmarshal(*rsv, &glob, &path)
	if err != nil {
		t.Error(err)
	}

	if e := "*.png"; e != glob {
		t.Errorf("got: %s wanted: %s", e, glob)
	}

	if e := "139"; e != path {
		t.Errorf("got: %s wanted: %s", e, path)
	}

}
Пример #18
0
func TestFuncImageURL(t *testing.T) {
	comp, err := libsass.New(nil, nil,
		libsass.BuildDir("../test/build"),
		libsass.ImgDir("../test/img"),
	)
	if err != nil {
		t.Fatal(err)
	}
	ctx := libsass.NewCompilerContext(comp)

	usv, _ := libsass.Marshal([]string{"139.png"})
	rsv, err := ImageURL(ctx, usv)
	if err != nil {
		t.Fatal(err)
	}
	var path string
	err = libsass.Unmarshal(*rsv, &path)
	if err != nil {
		t.Fatal(err)
	}
	if e := "url('../img/139.png')"; e != path {
		t.Errorf("got: %s wanted: %s", path, e)
	}

	// Test sending invalid date to imageURL
	usv, _ = libsass.Marshal(libs.SassNumber{Value: 1, Unit: "px"})
	_, err = ImageURL(ctx, usv)
	if err == nil {
		t.Fatal("error is nil")
	}

	e := "Invalid Sass type expected: slice got: libs.SassNumber value: 1px"

	if e != err.Error() {
		t.Errorf("got: %s wanted: %s", err, e)
	}

}
Пример #19
0
// FontURL builds a relative path to the requested font file from the built CSS.
func FontURL(ctx *libsass.Context, usv libsass.UnionSassValue) libsass.UnionSassValue {

	var (
		path, format string
		csv          libsass.UnionSassValue
		raw          bool
	)
	err := libsass.Unmarshal(usv, &path, &raw)

	if err != nil {
		return libsass.Error(err)
	}

	// Enter warning
	if ctx.FontDir == "." || ctx.FontDir == "" {
		s := "font-url: font path not set"
		fmt.Println(s)
		res, _ := libsass.Marshal(s)
		return res
	}

	rel, err := filepath.Rel(ctx.BuildDir, ctx.FontDir)

	if err != nil {
		return libsass.Error(err)
	}
	if raw {
		format = "%s"
	} else {
		format = `url("%s")`
	}

	csv, err = libsass.Marshal(fmt.Sprintf(format, filepath.Join(rel, path)))
	if err != nil {
		return libsass.Error(err)
	}
	return csv
}
Пример #20
0
// Sprite returns the source and background position for an image in the
// spritesheet.
func Sprite(ctx context.Context, usv libsass.SassValue) (rsv *libsass.SassValue, err error) {

	comp, err := libsass.CompFromCtx(ctx)
	if err != nil {
		return nil, err
	}

	pather := comp.(libsass.Pather)

	var glob, name string
	var offsetX, offsetY libs.SassNumber
	err = libsass.Unmarshal(usv, &glob, &name, &offsetX, &offsetY)
	if err != nil {
		if err == libsass.ErrSassNumberNoUnit {
			err := fmt.Errorf(
				"Please specify unit for offset ie. (2px)")
			return nil, err
		}
		return nil, err
	}

	loadctx := comp.Payload()

	sprites := payload.Sprite(loadctx)

	imgs := sprites.Get(glob)
	if imgs == nil {
		err := fmt.Errorf(
			"Variable not found matching glob: %s sprite:%s", glob, name)
		return nil, err
	}

	path, err := imgs.OutputPath()
	if err != nil {
		return nil, err
	}

	buildDir := pather.BuildDir()
	genImgDir := pather.ImgBuildDir()
	httpPath := pather.HTTPPath()

	// FIXME: path directory can not be trusted, rebuild this from the context
	if len(httpPath) == 0 {
		ctxPath, err := filepath.Rel(buildDir, genImgDir)
		if err != nil {
			return nil, err
		}
		path = strings.Join([]string{ctxPath, filepath.Base(path)}, "/")
	} else {
		u, err := url.Parse(httpPath)
		if err != nil {
			return nil, err
		}
		u.Path = strings.Join([]string{u.Path, "build", filepath.Base(path)}, "/")
		path = u.String()
	}
	if err != nil {
		return nil, err
	}

	if imgs.Lookup(name) == -1 {
		return nil, fmt.Errorf("image %s not found\n"+
			"   try one of these: %v", name, imgs.Paths())
	}
	// This is an odd name for what it does
	pos := imgs.GetPack(imgs.Lookup(name))

	if err != nil {
		return nil, err
	}

	x := libs.SassNumber{Unit: "px", Value: float64(-pos.X)}
	x = x.Add(offsetX)

	y := libs.SassNumber{Unit: "px", Value: float64(-pos.Y)}
	y = y.Add(offsetY)

	str, err := libsass.Marshal(
		fmt.Sprintf(`url("%s") %s %s`,
			path, x, y,
		))
	if err != nil {
		return nil, err
	}

	return &str, nil
}
Пример #21
0
// ImageHeight takes a file path (or sprite glob) and returns the
// height in pixels of the image being referenced.
func ImageHeight(mainctx context.Context, usv libsass.SassValue) (*libsass.SassValue, error) {
	var (
		glob string
		name string
	)

	comp, err := libsass.CompFromCtx(mainctx)
	if err != nil {
		return nil, err
	}

	err = libsass.Unmarshal(usv, &name)
	// Check for sprite-file override first
	if err != nil {
		var inf interface{}
		var infs []interface{}
		// Can't unmarshal to []interface{}, so unmarshal to
		// interface{} then reflect it into a []interface{}
		err = libsass.Unmarshal(usv, &inf)
		k := reflect.ValueOf(&infs).Elem()
		k.Set(reflect.ValueOf(inf))

		if err != nil {
			return nil, err
		}
		glob = infs[0].(string)
		name = infs[1].(string)
	}
	paths := comp.(libsass.Pather)
	imgs := sw.New(&sw.Options{
		ImageDir:  paths.ImgDir(),
		BuildDir:  paths.BuildDir(),
		GenImgDir: paths.ImgBuildDir(),
	})

	loadctx := comp.Payload()
	if loadctx == nil {
		return nil, ErrPayloadNil
	}

	images := payload.Image(loadctx)
	if images == nil {
		return nil, errors.New("inline payload not available")
	}

	if len(glob) == 0 {
		exst := images.Get(name)
		if exst != nil {
			imgs = exst
		} else {
			imgs.Decode(name)
			// Store images in global cache
			images.Set(name, imgs)
		}
	} else {
		sprites := payload.Sprite(loadctx)
		imgs = sprites.Get(glob)
		if imgs == nil {
			return nil, errors.New("Sprite not found")
		}
	}
	height := imgs.SImageHeight(name)
	Hheight := libs.SassNumber{
		Value: float64(height),
		Unit:  "px",
	}
	res, err := libsass.Marshal(Hheight)
	return &res, err
}
Пример #22
0
// SpriteMap returns a sprite from the passed glob and sprite
// parameters.
func SpriteMap(mainctx context.Context, usv libsass.SassValue) (*libsass.SassValue, error) {
	var glob string
	var spacing libs.SassNumber
	err := libsass.Unmarshal(usv, &glob, &spacing)
	if err != nil {
		return nil, err
	}
	comp, err := libsass.CompFromCtx(mainctx)
	if err != nil {
		return nil, err
	}
	paths := comp.(libsass.Pather)
	imgs := sw.New(&sw.Options{
		ImageDir:  paths.ImgDir(),
		BuildDir:  paths.BuildDir(),
		GenImgDir: paths.ImgBuildDir(),
		Padding:   int(spacing.Value),
	})
	if cglob, err := strconv.Unquote(glob); err == nil {
		glob = cglob
	}

	key := glob + strconv.FormatInt(int64(spacing.Value), 10)

	loadctx := comp.Payload()
	sprites := payload.Sprite(loadctx)

	// FIXME: wtf is this?
	// sprites.RLock()
	// if _, ok := sprites.M[key]; ok {
	// 	defer sprites.RUnlock()
	// 	res, err := libsass.Marshal(key)
	// 	if err != nil {
	// 		return setErrorAndReturn(err, rsv)
	// 	}
	// 	if rsv != nil {
	// 		*rsv = res
	// 	}
	// 	return nil
	// }
	// sprites.RUnlock()

	err = imgs.Decode(glob)
	if err != nil {
		return nil, err
	}

	_, err = imgs.Export()
	if err != nil {
		return nil, err
	}

	res, err := libsass.Marshal(key)
	if err != nil {
		return nil, err
	}

	sprites.Set(key, imgs)

	return &res, nil
}