Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add scss parsing to the extension #12

Merged
merged 4 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"require": {
"mck89/peast": "^1.16"
"mck89/peast": "^1.16",
"scssphp/scssphp": "^1.13.0"
},
"require-dev": {
"liquipedia/sqllint": "*",
Expand Down
4 changes: 2 additions & 2 deletions extension.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ResourceLoaderArticles",
"version": "2.3.0",
"version": "2.4.0",
"author": [
"[https://fo-nttax.de Alex Winkler]"
],
Expand Down Expand Up @@ -57,4 +57,4 @@
}
},
"manifest_version": 2
}
}
2 changes: 1 addition & 1 deletion i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@
"resourceloaderarticles-success-delete": "Resource successfully deleted",

"resourceloaderarticles-help-page": "Page name of resource (excl. `MediaWiki:Common.[js|css]/`). Valid JS ends with `.js` and valid styling ends with `.css` or `.less`.",
"resourceloaderarticles-help-priority": "Priority for loading order of the resource (higher first), falls back to alphabetic order within a single priority class."
"resourceloaderarticles-help-priority": "Priority for loading order of the resource (higher first), falls back to alphabetic order within a single priority class. Priority is done in two groups: Less/CSS and SCSS. The first group will always be before the second."
}
5 changes: 4 additions & 1 deletion src/Hooks/MainHookHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public function onBeforePageDisplay( $out, $skin ): void {
}

/**
* Set the CONTENT_MODEL_CSS content handler for less files
* Set the CONTENT_MODEL_CSS content handler for less and scss files
*
* @param Title $title
* @param string &$model
Expand All @@ -94,6 +94,9 @@ public function onContentHandlerDefaultModelFor( $title, &$model ) {
if ( str_ends_with( $title->getText(), '.less' ) ) {
$model = CONTENT_MODEL_CSS;
return true;
} elseif ( str_ends_with( $title->getText(), '.scss' ) ) {
$model = CONTENT_MODEL_CSS;
return true;
}
}
}
Expand Down
69 changes: 42 additions & 27 deletions src/ResourceLoader/ResourceLoaderArticlesModule.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use ResourceLoader;
use ResourceLoaderContext;
use ResourceLoaderWikiModule;
use ScssPhp\ScssPhp\Compiler as SCSSCompiler;

class ResourceLoaderArticlesModule extends ResourceLoaderWikiModule {

Expand All @@ -38,7 +39,11 @@ protected function getPages( ResourceLoaderContext $context ) {
foreach ( $articles as $article ) {
if ( substr( $article, -3 ) === '.js' ) {
$pages[ 'MediaWiki:Common.js/' . $article ] = [ 'type' => 'script' ];
} elseif ( substr( $article, -4 ) === '.css' || substr( $article, -5 ) === '.less' ) {
} elseif (
substr( $article, -4 ) === '.css'
|| substr( $article, -5 ) === '.less'
|| substr( $article, -5 ) === '.scss'
) {
$pages[ 'MediaWiki:Common.css/' . $article ] = [ 'type' => 'style' ];
}
}
Expand Down Expand Up @@ -99,12 +104,12 @@ static function () use ( $contents, $fileName ) {
* @return array
*/
public function getStyles( ResourceLoaderContext $context ) {
$styles = [];
$less = '';
$scss = '';
foreach ( $this->getPages( $context ) as $titleText => $options ) {
if ( $options[ 'type' ] !== 'style' ) {
continue;
}
$media = isset( $options[ 'media' ] ) ? $options[ 'media' ] : 'all';
$style = $this->getContent( $titleText, $context );
if ( strval( $style ) === '' ) {
continue;
Expand All @@ -114,33 +119,43 @@ public function getStyles( ResourceLoaderContext $context ) {
$style = '/* using @import is forbidden */';
}

if ( !isset( $styles[ $media ] ) ) {
$styles[ $media ] = [];
$styles[ $media ][ 0 ] = '';
}
$style = ResourceLoader::makeComment( $titleText ) . $style;
$styles[ $media ][ 0 ] .= $style;
}
foreach ( $styles as $media => $styleItem ) {
/* start of less parser */
try {
$lessc = new Less_Parser;
$lessc->parse( $styleItem[ 0 ] );
$style = $lessc->getCss();
} catch ( exception $e ) {
$style = '/* invalid less: ' . $e->getMessage() . ' */';
}
/* end of less parser */
if ( $this->getFlip( $context ) ) {
$style = CSSJanus::transform( $style, true, false );
if ( substr( $titleText, -5 ) === '.scss' ) {
$scss .= $style;
} else {
$less .= $style;
}
$style = MemoizedCallable::call(
'CSSMin::remap',
[ $style, false, $this->getConfig()->get( 'ScriptPath' ), true ]
);
$styles[ $media ][ 0 ] = $style;
}
return $styles;
/* start of less parser */
try {
$lessc = new Less_Parser;
$lessc->parse( $less );
$compiledLess = $lessc->getCss();
} catch ( \Exception $e ) {
$compiledLess = '/* invalid less: ' . $e->getMessage() . ' */';
}
/* end of less parser */

/* start of scss parser */
try {
$compiler = new SCSSCompiler();
$compiledScss = $compiler->compileString( $scss )->getCss();
} catch ( \Exception $e ) {
$compiledScss = '/* invalid scss: ' . $e->getMessage() . ' */';
}
/* end of scss parser */

$css = $compiledLess . $compiledScss;

if ( $this->getFlip( $context ) ) {
$css = CSSJanus::transform( $css, true, false );
}
$css = MemoizedCallable::call(
'CSSMin::remap',
[ $css, false, $this->getConfig()->get( 'ScriptPath' ), true ]
);

return [ 'all' => [ $css ] ];
}

/**
Expand Down
13 changes: 10 additions & 3 deletions src/SpecialPage/SpecialResourceLoaderArticles.php
Original file line number Diff line number Diff line change
Expand Up @@ -346,11 +346,18 @@ public function trimValueCB( $value ) {
*/
public function validatePageCB( $value, $alldata ) {
if (
( $alldata[ 'Type' ] === 'style'
&& !( ( strlen( $value ) > 4 && substr( $value, -4 ) === '.css' )
(
$alldata[ 'Type' ] === 'style'
&& !(
( strlen( $value ) > 4 && substr( $value, -4 ) === '.css' )
|| ( strlen( $value ) > 5 && substr( $value, -5 ) === '.less' )
|| ( strlen( $value ) > 5 && substr( $value, -5 ) === '.scss' )
)
) || ( $alldata[ 'Type' ] === 'script' && !( strlen( $value ) > 3 && substr( $value, -3 ) === '.js' ) )
)
|| (
$alldata[ 'Type' ] === 'script'
&& !( strlen( $value ) > 3 && substr( $value, -3 ) === '.js' )
)
) {
return $this->msg( 'resourceloaderarticles-error-page-invalid' )->text();
}
Expand Down