Skip to content

Commit

Permalink
Less_Parser: Refactor import_callback option and add tests and docs
Browse files Browse the repository at this point in the history
Move to Environment object so that it is more stable, instead of
relying on static access to the last-created Parser instance.
Follows-up If4a0a7ce052f.

Deprecate it in favour of the SetImportDirs() callback.

Change-Id: Ic238df44218c5ef72b55f3718f4b0bebaa19dbff
  • Loading branch information
Krinkle committed Mar 26, 2024
1 parent 51c4f72 commit 3539122
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 81 deletions.
17 changes: 17 additions & 0 deletions lib/Less/Environment.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ class Less_Environment {

public $strictMath = false;

public $importCallback = null;

/**
* @var array
*/
Expand Down Expand Up @@ -115,6 +117,21 @@ public static function isPathRelative( $path ) {
return !preg_match( '/^(?:[a-z-]+:|\/|#)/', $path );
}

/**
* Apply legacy 'import_callback' option.
*
* See Less_Parser::$default_options to learn more about the 'import_callback' option.
* This option is deprecated in favour of Less_Parser::SetImportDirs.
*
* @param Less_Tree_Import $importNode
* @return array{0:string,1:string|null}|null Array containing path and (optional) uri or null
*/
public function callImportCallback( Less_Tree_Import $importNode ) {
if ( is_callable( $this->importCallback ) ) {
return ( $this->importCallback )( $importNode );
}
}

/**
* Canonicalize a path by resolving references to '/./', '/../'
* Does not remove leading "../"
Expand Down
3 changes: 1 addition & 2 deletions lib/Less/ImportVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,7 @@ public function processImportNode( $importNode, $env, &$importParent ) {
// import dirs resolution logic.
// TODO: We might need upstream's `tryAppendLessExtension` logic here.
// We currenlty do do this in getPath instead.
$callback = Less_Parser::$options['import_callback'];
$path_and_uri = is_callable( $callback ) ? $callback( $importNode ) : null;
$path_and_uri = $env->callImportCallback( $importNode );
if ( !$path_and_uri ) {
$path_and_uri = $importNode->PathAndUri();
}
Expand Down
27 changes: 27 additions & 0 deletions lib/Less/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,29 @@ class Less_Parser {
'numPrecision' => 8,

'import_dirs' => [],

// Override how imported file names are resolved.
//
// This legacy calllback exposes internal objects and their implementation
// details and is therefore deprecated. Use Less_Parser::SetImportDirs instead
// to override the resolution of imported file names.
//
// Example:
//
// $parser = new Less_Parser( [
// 'import_callback' => function ( $importNode ) {
// $path = $importNode->getPath();
// if ( $path === 'special.less' ) {
// return [ $mySpecialFilePath, null ];
// }
// }
// ] );
//
// @since 1.5.1
// @deprecated since 4.3.0
// @see Less_Environment::callImportCallback
// @see Less_Parser::SetImportDirs
//
'import_callback' => null,
'cache_dir' => null,
'cache_method' => 'serialize', // false, 'serialize', 'callback';
Expand Down Expand Up @@ -133,6 +156,10 @@ public function SetOption( $option, $value ) {
$this->SetImportDirs( $value );
return;

case 'import_callback':
$this->env->importCallback = $value;
return;

case 'cache_dir':
if ( is_string( $value ) ) {
Less_Cache::SetCacheDir( $value );
Expand Down
5 changes: 2 additions & 3 deletions lib/Less/Tree/Import.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,7 @@ public function compile( $env ) {
// about Less_Tree_Import::PathAndUri() is fixed, this can be removed by letting
// skip() call $this->PathAndUri() on its own.
// get path & uri
$callback = Less_Parser::$options['import_callback'];
$path_and_uri = is_callable( $callback ) ? $callback( $this ) : null;
$path_and_uri = $env->callImportCallback( $this );
if ( !$path_and_uri ) {
$path_and_uri = $this->PathAndUri();
}
Expand Down Expand Up @@ -217,7 +216,7 @@ public function compile( $env ) {
*/
public function PathAndUri() {
$evald_path = $this->getPath();
// TODO: Move 'import_callback' and getPath() fallback logic from callers
// TODO: Move callImportCallback() and getPath() fallback logic from callers
// to here so that PathAndUri() is equivalent to upstream fileManager.getPath()

if ( $evald_path ) {
Expand Down
76 changes: 0 additions & 76 deletions test/phpunit/ImportDirsTest.php

This file was deleted.

88 changes: 88 additions & 0 deletions test/phpunit/ParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,94 @@ public function testGetParsedFiles() {
);
}

public static function provideSetImportDirs() {
yield 'from-importdir' => [
'from-importdir.less',
[
__DIR__ . '/data/importdir-somevars/' => '',
],
'div{font-family:monospace}'
];
yield 'from-importdir-file' => [
'from-importdir-file.less',
[
__DIR__ . '/data/importdir-somevars/' => '',
],
'div{font-family:fantasy}'
];
yield 'from-importdir-filenosuffix' => [
'from-importdir-filenosuffix.less',
[
__DIR__ . '/data/importdir-somevars/' => '',
],
'div{font-family:fantasy}'
];
yield 'from-importcallback (backcompat)' => [
'from-importcallback.less',
[
__DIR__ . '/data/importdir-somevars/' => '',
static function ( $path ) {
// Backwards compatibility with how people used
// less.php 4.0.0 and earlier.
if ( $path === '@wikimedia/example.less' ) {
return [
Less_Environment::normalizePath( __DIR__ . '/data/importdir-somevars/callme.less' ),
Less_Environment::normalizePath( dirname( $path ) )
];
}
return [ null, null ];
}
],
'div{font-family:Call Me Maybe}'
];
yield 'from-importcallback (new)' => [
'from-importcallback.less',
[
__DIR__ . '/data/importdir-somevars/' => '',
static function ( $path ) {
if ( $path === '@wikimedia/example.less' ) {
return [
__DIR__ . '/data/importdir-somevars/callme.less',
null
];
}
}
],
'div{font-family:Call Me Maybe}'
];
}

/**
* @dataProvider provideSetImportDirs
*/
public function testSetImportDirs( string $input, array $importDirs, string $expect ) {
$file = __DIR__ . '/data/consume-somevars/' . $input;

$parser = new Less_Parser( [
'compress' => true,
] );
$parser->SetImportDirs( $importDirs );
$parser->parseFile( $file );

$this->assertEquals( $expect, $parser->getCss() );
}

public function testImportCallback() {
$file = __DIR__ . '/data/consume-somevars/from-importcallback.less';

$parser = new Less_Parser( [
'compress' => true,
'import_callback' => static function ( $importNode ) {
if ( $importNode->getPath() === '@wikimedia/example.less' ) {
return [ __DIR__ . '/data/importdir-somevars/callme.less', '/site' ];
}
}
] );
$parser->parseFile( $file );

$this->assertEquals( 'div{font-family:Call Me Maybe}', $parser->getCss() );
}

public function testOperationException() {
$lessFile = __DIR__ . '/data/exception/f2.less';

Expand Down

0 comments on commit 3539122

Please sign in to comment.