diff options
| author | Indrajith K L | 2022-12-03 17:00:20 +0530 | 
|---|---|---|
| committer | Indrajith K L | 2022-12-03 17:00:20 +0530 | 
| commit | f5c4671bfbad96bf346bd7e9a21fc4317b4959df (patch) | |
| tree | 2764fc62da58f2ba8da7ed341643fc359873142f /v_windows/v/old/vlib/vweb/assets | |
| download | cli-tools-windows-f5c4671bfbad96bf346bd7e9a21fc4317b4959df.tar.gz cli-tools-windows-f5c4671bfbad96bf346bd7e9a21fc4317b4959df.tar.bz2 cli-tools-windows-f5c4671bfbad96bf346bd7e9a21fc4317b4959df.zip | |
Diffstat (limited to 'v_windows/v/old/vlib/vweb/assets')
| -rw-r--r-- | v_windows/v/old/vlib/vweb/assets/assets.v | 201 | ||||
| -rw-r--r-- | v_windows/v/old/vlib/vweb/assets/assets_test.v | 179 | 
2 files changed, 380 insertions, 0 deletions
| diff --git a/v_windows/v/old/vlib/vweb/assets/assets.v b/v_windows/v/old/vlib/vweb/assets/assets.v new file mode 100644 index 0000000..1240e41 --- /dev/null +++ b/v_windows/v/old/vlib/vweb/assets/assets.v @@ -0,0 +1,201 @@ +module assets + +// this module provides an AssetManager for combining +// and caching javascript & css. +import os +import time +import crypto.md5 + +const ( +	unknown_asset_type_error = 'vweb.assets: unknown asset type' +) + +struct AssetManager { +mut: +	css []Asset +	js  []Asset +pub mut: +	// when true assets will be minified +	minify bool +	// the directory to store the cached/combined files +	cache_dir string +} + +struct Asset { +	file_path     string +	last_modified time.Time +} + +// new_manager returns a new AssetManager +pub fn new_manager() &AssetManager { +	return &AssetManager{} +} + +// add_css adds a css asset +pub fn (mut am AssetManager) add_css(file string) bool { +	return am.add('css', file) +} + +// add_js adds a js asset +pub fn (mut am AssetManager) add_js(file string) bool { +	return am.add('js', file) +} + +// combine_css returns the combined css as a string when to_file is false +// when to_file is true it combines the css to disk and returns the path of the file +pub fn (am AssetManager) combine_css(to_file bool) string { +	return am.combine('css', to_file) +} + +// combine_js returns the combined js as a string when to_file is false +// when to_file is true it combines the css to disk and returns the path of the file +pub fn (am AssetManager) combine_js(to_file bool) string { +	return am.combine('js', to_file) +} + +// include_css returns the html <link> tag(s) for including the css files in a page. +// when combine is true the files are combined. +pub fn (am AssetManager) include_css(combine bool) string { +	return am.include('css', combine) +} + +// include_js returns the html <script> tag(s) for including the js files in a page. +// when combine is true the files are combined. +pub fn (am AssetManager) include_js(combine bool) string { +	return am.include('js', combine) +} + +fn (am AssetManager) combine(asset_type string, to_file bool) string { +	if am.cache_dir == '' { +		panic('vweb.assets: you must set a cache dir.') +	} +	cache_key := am.get_cache_key(asset_type) +	out_file := '$am.cache_dir/${cache_key}.$asset_type' +	mut out := '' +	// use cache +	if os.exists(out_file) { +		if to_file { +			return out_file +		} +		cached := os.read_file(out_file) or { return '' } +		return cached +	} +	// rebuild +	for asset in am.get_assets(asset_type) { +		data := os.read_file(asset.file_path) or { return '' } +		out += data +	} +	if am.minify { +		if asset_type == 'css' { +			out = minify_css(out) +		} else { +			out = minify_js(out) +		} +	} +	if !to_file { +		return out +	} +	if !os.is_dir(am.cache_dir) { +		os.mkdir(am.cache_dir) or { panic(err) } +	} +	mut file := os.create(out_file) or { panic(err) } +	file.write(out.bytes()) or { panic(err) } +	file.close() +	return out_file +} + +fn (am AssetManager) get_cache_key(asset_type string) string { +	mut files_salt := '' +	mut latest_modified := u64(0) +	for asset in am.get_assets(asset_type) { +		files_salt += asset.file_path +		if asset.last_modified.unix > latest_modified { +			latest_modified = asset.last_modified.unix +		} +	} +	hash := md5.sum(files_salt.bytes()).hex() +	return '$hash-$latest_modified' +} + +fn (am AssetManager) include(asset_type string, combine bool) string { +	assets := am.get_assets(asset_type) +	mut out := '' +	if asset_type == 'css' { +		if combine { +			file := am.combine(asset_type, true) +			return '<link rel="stylesheet" href="$file">\n' +		} +		for asset in assets { +			out += '<link rel="stylesheet" href="$asset.file_path">\n' +		} +	} +	if asset_type == 'js' { +		if combine { +			file := am.combine(asset_type, true) +			return '<script type="text/javascript" src="$file"></script>\n' +		} +		for asset in assets { +			out += '<script type="text/javascript" src="$asset.file_path"></script>\n' +		} +	} +	return out +} + +// dont return option until size limit is removed +// fn (mut am AssetManager) add(asset_type, file string) ?bool { +fn (mut am AssetManager) add(asset_type string, file string) bool { +	if !os.exists(file) { +		// return error('vweb.assets: cannot add asset $file, it does not exist') +		return false +	} +	asset := Asset{ +		file_path: file +		last_modified: time.Time{ +			unix: u64(os.file_last_mod_unix(file)) +		} +	} +	if asset_type == 'css' { +		am.css << asset +	} else if asset_type == 'js' { +		am.js << asset +	} else { +		panic('$assets.unknown_asset_type_error ($asset_type).') +	} +	return true +} + +fn (am AssetManager) exists(asset_type string, file string) bool { +	assets := am.get_assets(asset_type) +	for asset in assets { +		if asset.file_path == file { +			return true +		} +	} +	return false +} + +fn (am AssetManager) get_assets(asset_type string) []Asset { +	if asset_type != 'css' && asset_type != 'js' { +		panic('$assets.unknown_asset_type_error ($asset_type).') +	} +	assets := if asset_type == 'css' { am.css } else { am.js } +	return assets +} + +// todo: implement proper minification +pub fn minify_css(css string) string { +	mut lines := css.split('\n') +	for i, _ in lines { +		lines[i] = lines[i].trim_space() +	} +	return lines.join(' ') +} + +// todo: implement proper minification +pub fn minify_js(js string) string { +	mut lines := js.split('\n') +	for i, _ in lines { +		lines[i] = lines[i].trim_space() +	} +	return lines.join(' ') +} diff --git a/v_windows/v/old/vlib/vweb/assets/assets_test.v b/v_windows/v/old/vlib/vweb/assets/assets_test.v new file mode 100644 index 0000000..6170f3c --- /dev/null +++ b/v_windows/v/old/vlib/vweb/assets/assets_test.v @@ -0,0 +1,179 @@ +import vweb.assets +import os + +// clean_cache_dir used before and after tests that write to a cache directory. +// Because of parallel compilation and therefore test running, +// unique cache dirs are needed per test function. +fn clean_cache_dir(dir string) { +	if os.is_dir(dir) { +		os.rmdir_all(dir) or { panic(err) } +	} +} + +fn base_cache_dir() string { +	return os.join_path(os.temp_dir(), 'assets_test_cache') +} + +fn cache_dir(test_name string) string { +	return os.join_path(base_cache_dir(), test_name) +} + +fn get_test_file_path(file string) string { +	path := os.join_path(base_cache_dir(), file) +	if !os.is_dir(base_cache_dir()) { +		os.mkdir_all(base_cache_dir()) or { panic(err) } +	} +	if !os.exists(path) { +		os.write_file(path, get_test_file_contents(file)) or { panic(err) } +	} +	return path +} + +fn get_test_file_contents(file string) string { +	contents := match file { +		'test1.js' { '{"one": 1}\n' } +		'test2.js' { '{"two": 2}\n' } +		'test1.css' { '.one {\n\tcolor: #336699;\n}\n' } +		'test2.css' { '.two {\n\tcolor: #996633;\n}\n' } +		else { 'wibble\n' } +	} +	return contents +} + +fn test_set_cache() { +	mut am := assets.new_manager() +	am.cache_dir = 'cache' +} + +fn test_set_minify() { +	mut am := assets.new_manager() +	am.minify = true +} + +fn test_add() { +	mut am := assets.new_manager() +	assert am.add('css', 'testx.css') == false +	assert am.add('css', get_test_file_path('test1.css')) == true +	assert am.add('js', get_test_file_path('test1.js')) == true +	// assert am.add('css', get_test_file_path('test2.js')) == false // TODO: test extension on add +} + +fn test_add_css() { +	mut am := assets.new_manager() +	assert am.add_css('testx.css') == false +	assert am.add_css(get_test_file_path('test1.css')) == true +	// assert am.add_css(get_test_file_path('test1.js')) == false // TODO: test extension on add +} + +fn test_add_js() { +	mut am := assets.new_manager() +	assert am.add_js('testx.js') == false +	assert am.add_css(get_test_file_path('test1.js')) == true +	// assert am.add_css(get_test_file_path('test1.css')) == false // TODO: test extension on add +} + +fn test_combine_css() { +	mut am := assets.new_manager() +	am.cache_dir = cache_dir('test_combine_css') +	clean_cache_dir(am.cache_dir) +	am.add_css(get_test_file_path('test1.css')) +	am.add_css(get_test_file_path('test2.css')) +	// TODO: How do I test non-minified, is there a "here doc" format that keeps formatting? +	am.minify = true +	expected := '.one { color: #336699; } .two { color: #996633; } ' +	actual := am.combine_css(false) +	assert actual == expected +	assert actual.contains(expected) +	// Test cache path doesn't change when input files and minify setting do not. +	path1 := am.combine_css(true) +	clean_cache_dir(am.cache_dir) +	path2 := am.combine_css(true) +	assert path1 == path2 +	clean_cache_dir(am.cache_dir) +} + +fn test_combine_js() { +	mut am := assets.new_manager() +	am.cache_dir = cache_dir('test_combine_js') +	clean_cache_dir(am.cache_dir) +	am.add_js(get_test_file_path('test1.js')) +	am.add_js(get_test_file_path('test2.js')) +	expected1 := '{"one": 1}' +	expected2 := '{"two": 2}' +	expected := expected1 + '\n' + expected2 + '\n' +	actual := am.combine_js(false) +	assert actual == expected +	assert actual.contains(expected) +	assert actual.contains(expected1) +	assert actual.contains(expected2) +	am.minify = true +	clean_cache_dir(am.cache_dir) +	expected3 := expected1 + ' ' + expected2 + ' ' +	actual2 := am.combine_js(false) +	assert actual2 == expected3 +	assert actual2.contains(expected3) +	// Test cache path doesn't change when input files and minify setting do not. +	path1 := am.combine_js(true) +	clean_cache_dir(am.cache_dir) +	path2 := am.combine_js(true) +	assert path1 == path2 +	clean_cache_dir(am.cache_dir) +} + +fn test_include_css() { +	mut am := assets.new_manager() +	file1 := get_test_file_path('test1.css') +	am.add_css(file1) +	expected := '<link rel="stylesheet" href="$file1">\n' +	actual := am.include_css(false) +	assert actual == expected +	assert actual.contains(expected) +	// Two lines of output. +	file2 := get_test_file_path('test2.css') +	am.add_css(file2) +	am.cache_dir = cache_dir('test_include_css') +	clean_cache_dir(am.cache_dir) +	expected2 := expected + '<link rel="stylesheet" href="$file2">\n' +	actual2 := am.include_css(false) +	assert actual2 == expected2 +	assert actual2.contains(expected2) +	// Combined output. +	clean_cache_dir(am.cache_dir) +	actual3 := am.include_css(true) +	assert actual3.contains(expected2) == false +	assert actual3.starts_with('<link rel="stylesheet" href="$am.cache_dir/') == true +	// Test cache path doesn't change when input files and minify setting do not. +	clean_cache_dir(am.cache_dir) +	actual4 := am.include_css(true) +	assert actual4 == actual3 +	clean_cache_dir(am.cache_dir) +} + +fn test_include_js() { +	mut am := assets.new_manager() +	file1 := get_test_file_path('test1.js') +	am.add_js(file1) +	expected := '<script type="text/javascript" src="$file1"></script>\n' +	actual := am.include_js(false) +	assert actual == expected +	assert actual.contains(expected) +	// Two lines of output. +	file2 := get_test_file_path('test2.js') +	am.add_js(file2) +	am.cache_dir = cache_dir('test_include_js') +	clean_cache_dir(am.cache_dir) +	expected2 := expected + '<script type="text/javascript" src="$file2"></script>\n' +	actual2 := am.include_js(false) +	assert actual2 == expected2 +	assert actual2.contains(expected2) +	// Combined output. +	clean_cache_dir(am.cache_dir) +	actual3 := am.include_js(true) +	assert actual3.contains(expected2) == false +	assert actual3.starts_with('<script type="text/javascript" src="$am.cache_dir/') +	// Test cache path doesn't change when input files and minify setting do not. +	clean_cache_dir(am.cache_dir) +	actual4 := am.include_js(true) +	assert actual4 == actual3 +	clean_cache_dir(am.cache_dir) +} | 
