@parcel/transformer-sass
Advanced tools
Comparing version 2.0.0-canary.1733 to 2.0.0-canary.1735
@@ -21,33 +21,5 @@ "use strict"; | ||
} | ||
function _os() { | ||
const data = require("os"); | ||
_os = function () { | ||
return data; | ||
}; | ||
return data; | ||
} | ||
function _sourceMap() { | ||
const data = _interopRequireDefault(require("@parcel/source-map")); | ||
_sourceMap = function () { | ||
return data; | ||
}; | ||
return data; | ||
} | ||
function _sass() { | ||
const data = _interopRequireDefault(require("sass")); | ||
_sass = function () { | ||
return data; | ||
}; | ||
return data; | ||
} | ||
function _util() { | ||
const data = require("util"); | ||
_util = function () { | ||
return data; | ||
}; | ||
return data; | ||
} | ||
var _legacy = require("./legacy"); | ||
var _modern = require("./modern"); | ||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } | ||
// E.g: ~library/file.sass | ||
const NODE_MODULE_ALIAS_RE = /^~[^/\\]/; | ||
var _default = exports.default = new (_plugin().Transformer)({ | ||
@@ -69,20 +41,33 @@ async loadConfig({ | ||
} | ||
let version = detectVersion(configResult); | ||
if (version === 'legacy') { | ||
// Resolve relative paths from config file | ||
if (configFile && configResult.includePaths) { | ||
configResult.includePaths = configResult.includePaths.map(p => _path().default.resolve(_path().default.dirname(configFile.filePath), p)); | ||
} | ||
if (configResult.importer === undefined) { | ||
configResult.importer = []; | ||
} else if (!Array.isArray(configResult.importer)) { | ||
configResult.importer = [configResult.importer]; | ||
} | ||
// Resolve relative paths from config file | ||
if (configFile && configResult.includePaths) { | ||
configResult.includePaths = configResult.includePaths.map(p => _path().default.resolve(_path().default.dirname(configFile.filePath), p)); | ||
// Always emit sourcemap | ||
configResult.sourceMap = true; | ||
// sources are created relative to the directory of outFile | ||
configResult.outFile = _path().default.join(options.projectRoot, 'style.css.map'); | ||
configResult.omitSourceMapUrl = true; | ||
configResult.sourceMapContents = false; | ||
} else if (version === 'modern') { | ||
// Resolve relative paths from config file | ||
if (configFile && configResult.loadPaths) { | ||
configResult.loadPaths = configResult.loadPaths.map(p => _path().default.resolve(_path().default.dirname(configFile.filePath), p)); | ||
} | ||
// Always emit sourcemap | ||
configResult.sourceMap = true; | ||
} | ||
if (configResult.importer === undefined) { | ||
configResult.importer = []; | ||
} else if (!Array.isArray(configResult.importer)) { | ||
configResult.importer = [configResult.importer]; | ||
} | ||
// Always emit sourcemap | ||
configResult.sourceMap = true; | ||
// sources are created relative to the directory of outFile | ||
configResult.outFile = _path().default.join(options.projectRoot, 'style.css.map'); | ||
configResult.omitSourceMapUrl = true; | ||
configResult.sourceMapContents = false; | ||
return configResult; | ||
return { | ||
version, | ||
config: configResult | ||
}; | ||
}, | ||
@@ -92,133 +77,39 @@ async transform({ | ||
options, | ||
config, | ||
config: { | ||
version, | ||
config | ||
}, | ||
resolve | ||
}) { | ||
let rawConfig = config ?? {}; | ||
let sassRender = (0, _util().promisify)(_sass().default.render.bind(_sass().default)); | ||
let css; | ||
try { | ||
let code = await asset.getCode(); | ||
let result = await sassRender({ | ||
...rawConfig, | ||
file: asset.filePath, | ||
data: rawConfig.data ? rawConfig.data + _os().EOL + code : code, | ||
importer: [...rawConfig.importer, resolvePathImporter({ | ||
asset, | ||
resolve, | ||
includePaths: rawConfig.includePaths, | ||
options | ||
})], | ||
indentedSyntax: typeof rawConfig.indentedSyntax === 'boolean' ? rawConfig.indentedSyntax : asset.type === 'sass' | ||
}); | ||
css = result.css; | ||
for (let included of result.stats.includedFiles) { | ||
if (included !== asset.filePath) { | ||
asset.invalidateOnFileChange(included); | ||
} | ||
} | ||
if (result.map != null) { | ||
let map = new (_sourceMap().default)(options.projectRoot); | ||
map.addVLQMap(JSON.parse(result.map)); | ||
asset.setMap(map); | ||
} | ||
} catch (err) { | ||
// Adapt the Error object for the reporter. | ||
err.fileName = err.file; | ||
err.loc = { | ||
line: err.line, | ||
column: err.column | ||
}; | ||
throw err; | ||
if (version === 'legacy') { | ||
await (0, _legacy.transformLegacy)(asset, config, resolve, options); | ||
} else { | ||
await (0, _modern.transformModern)(asset, config, resolve, options); | ||
} | ||
asset.type = 'css'; | ||
asset.setCode(css); | ||
return [asset]; | ||
} | ||
}); | ||
function resolvePathImporter({ | ||
asset, | ||
resolve, | ||
includePaths, | ||
options | ||
}) { | ||
// This is a reimplementation of the Sass resolution algorithm that uses Parcel's | ||
// FS and tracks all tried files so they are watched for creation. | ||
async function resolvePath(url, prev) { | ||
/* | ||
Imports are resolved by trying, in order: | ||
* Loading a file relative to the file in which the `@import` appeared. | ||
* Each custom importer. | ||
* Loading a file relative to the current working directory (This rule doesn't really make sense for Parcel). | ||
* Each load path in `includePaths` | ||
* Each load path specified in the `SASS_PATH` environment variable, which should be semicolon-separated on Windows and colon-separated elsewhere. | ||
See: https://sass-lang.com/documentation/js-api#importer | ||
See also: https://github.com/sass/dart-sass/blob/006e6aa62f2417b5267ad5cdb5ba050226fab511/lib/src/importer/node/implementation.dart | ||
*/ | ||
let paths = [_path().default.dirname(prev)]; | ||
if (includePaths) { | ||
paths.push(...includePaths); | ||
function detectVersion(config) { | ||
for (let legacyOption of ['data', 'indentType', 'indentWidth', 'linefeed', 'outputStyle', 'importer', 'pkgImporter', 'includePaths', 'omitSourceMapUrl', 'outFile', 'sourceMapContents', 'sourceMapEmbed', 'sourceMapRoot']) { | ||
if (config[legacyOption] != null) { | ||
return 'legacy'; | ||
} | ||
asset.invalidateOnEnvChange('SASS_PATH'); | ||
if (options.env.SASS_PATH) { | ||
paths.push(...options.env.SASS_PATH.split(process.platform === 'win32' ? ';' : ':').map(p => _path().default.resolve(options.projectRoot, p))); | ||
} | ||
for (let modernOption of ['loadPaths', 'sourceMapIncludeSources', 'style', 'importers']) { | ||
if (config[modernOption] != null) { | ||
return 'modern'; | ||
} | ||
const urls = [url]; | ||
const urlFileName = _path().default.basename(url); | ||
if (urlFileName[0] !== '_') { | ||
urls.push(_path().default.join(_path().default.dirname(url), `_${urlFileName}`)); | ||
} | ||
if (url[0] !== '~') { | ||
for (let p of paths) { | ||
for (let u of urls) { | ||
const filePath = _path().default.resolve(p, u); | ||
try { | ||
const contents = await asset.fs.readFile(filePath, 'utf8'); | ||
return { | ||
filePath, | ||
contents | ||
}; | ||
} catch (err) { | ||
asset.invalidateOnFileCreate({ | ||
filePath | ||
}); | ||
} | ||
} | ||
} | ||
if (typeof config.sourceMap === 'string') { | ||
return 'legacy'; | ||
} | ||
if (config.functions && typeof config.functions === 'object' && Object.keys(config.functions).length > 0) { | ||
for (let key in config.functions) { | ||
let fn = config.functions[key]; | ||
if (typeof fn === 'function' && fn.length > 1) { | ||
return 'legacy'; | ||
} | ||
} | ||
// If none of the default sass rules apply, try Parcel's resolver. | ||
for (let u of urls) { | ||
if (NODE_MODULE_ALIAS_RE.test(u)) { | ||
u = u.slice(1); | ||
} | ||
try { | ||
const filePath = await resolve(prev, u, { | ||
packageConditions: ['sass', 'style'] | ||
}); | ||
if (filePath) { | ||
const contents = await asset.fs.readFile(filePath, 'utf8'); | ||
return { | ||
filePath, | ||
contents | ||
}; | ||
} | ||
} catch (err) { | ||
continue; | ||
} | ||
} | ||
} | ||
return function (rawUrl, prev, done) { | ||
const url = rawUrl.replace(/^file:\/\//, ''); | ||
resolvePath(url, prev).then(resolved => { | ||
if (resolved) { | ||
done({ | ||
file: resolved.filePath, | ||
contents: resolved.contents | ||
}); | ||
} else { | ||
done(); | ||
} | ||
}).catch(done); | ||
}; | ||
return 'modern'; | ||
} |
{ | ||
"name": "@parcel/transformer-sass", | ||
"version": "2.0.0-canary.1733+96d88140e", | ||
"version": "2.0.0-canary.1735+f53f45037", | ||
"license": "MIT", | ||
@@ -20,10 +20,10 @@ "publishConfig": { | ||
"node": ">= 16.0.0", | ||
"parcel": "^2.0.0-canary.1731+96d88140e" | ||
"parcel": "^2.0.0-canary.1733+f53f45037" | ||
}, | ||
"dependencies": { | ||
"@parcel/plugin": "2.0.0-canary.1733+96d88140e", | ||
"@parcel/plugin": "2.0.0-canary.1735+f53f45037", | ||
"@parcel/source-map": "^2.1.1", | ||
"sass": "^1.38.0" | ||
"sass": "^1.79.4" | ||
}, | ||
"gitHead": "96d88140e14585945921e4a0142511c29c0f7d0f" | ||
"gitHead": "f53f4503799a07e3a01452f5e53ead44c30ebc53" | ||
} |
// @flow | ||
import {Transformer} from '@parcel/plugin'; | ||
import path from 'path'; | ||
import {EOL} from 'os'; | ||
import SourceMap from '@parcel/source-map'; | ||
import sass from 'sass'; | ||
import {promisify} from 'util'; | ||
import {transformLegacy} from './legacy'; | ||
import {transformModern} from './modern'; | ||
// E.g: ~library/file.sass | ||
const NODE_MODULE_ALIAS_RE = /^~[^/\\]/; | ||
export default (new Transformer({ | ||
@@ -30,75 +25,46 @@ async loadConfig({config, options}) { | ||
// Resolve relative paths from config file | ||
if (configFile && configResult.includePaths) { | ||
configResult.includePaths = configResult.includePaths.map(p => | ||
path.resolve(path.dirname(configFile.filePath), p), | ||
); | ||
} | ||
let version = detectVersion(configResult); | ||
if (configResult.importer === undefined) { | ||
configResult.importer = []; | ||
} else if (!Array.isArray(configResult.importer)) { | ||
configResult.importer = [configResult.importer]; | ||
} | ||
if (version === 'legacy') { | ||
// Resolve relative paths from config file | ||
if (configFile && configResult.includePaths) { | ||
configResult.includePaths = configResult.includePaths.map(p => | ||
path.resolve(path.dirname(configFile.filePath), p), | ||
); | ||
} | ||
// Always emit sourcemap | ||
configResult.sourceMap = true; | ||
// sources are created relative to the directory of outFile | ||
configResult.outFile = path.join(options.projectRoot, 'style.css.map'); | ||
configResult.omitSourceMapUrl = true; | ||
configResult.sourceMapContents = false; | ||
return configResult; | ||
}, | ||
async transform({asset, options, config, resolve}) { | ||
let rawConfig = config ?? {}; | ||
let sassRender = promisify(sass.render.bind(sass)); | ||
let css; | ||
try { | ||
let code = await asset.getCode(); | ||
let result = await sassRender({ | ||
...rawConfig, | ||
file: asset.filePath, | ||
data: rawConfig.data ? rawConfig.data + EOL + code : code, | ||
importer: [ | ||
...rawConfig.importer, | ||
resolvePathImporter({ | ||
asset, | ||
resolve, | ||
includePaths: rawConfig.includePaths, | ||
options, | ||
}), | ||
], | ||
indentedSyntax: | ||
typeof rawConfig.indentedSyntax === 'boolean' | ||
? rawConfig.indentedSyntax | ||
: asset.type === 'sass', | ||
}); | ||
css = result.css; | ||
for (let included of result.stats.includedFiles) { | ||
if (included !== asset.filePath) { | ||
asset.invalidateOnFileChange(included); | ||
} | ||
if (configResult.importer === undefined) { | ||
configResult.importer = []; | ||
} else if (!Array.isArray(configResult.importer)) { | ||
configResult.importer = [configResult.importer]; | ||
} | ||
if (result.map != null) { | ||
let map = new SourceMap(options.projectRoot); | ||
map.addVLQMap(JSON.parse(result.map)); | ||
asset.setMap(map); | ||
// Always emit sourcemap | ||
configResult.sourceMap = true; | ||
// sources are created relative to the directory of outFile | ||
configResult.outFile = path.join(options.projectRoot, 'style.css.map'); | ||
configResult.omitSourceMapUrl = true; | ||
configResult.sourceMapContents = false; | ||
} else if (version === 'modern') { | ||
// Resolve relative paths from config file | ||
if (configFile && configResult.loadPaths) { | ||
configResult.loadPaths = configResult.loadPaths.map(p => | ||
path.resolve(path.dirname(configFile.filePath), p), | ||
); | ||
} | ||
} catch (err) { | ||
// Adapt the Error object for the reporter. | ||
err.fileName = err.file; | ||
err.loc = { | ||
line: err.line, | ||
column: err.column, | ||
}; | ||
throw err; | ||
// Always emit sourcemap | ||
configResult.sourceMap = true; | ||
} | ||
asset.type = 'css'; | ||
asset.setCode(css); | ||
return {version, config: configResult}; | ||
}, | ||
async transform({asset, options, config: {version, config}, resolve}) { | ||
if (version === 'legacy') { | ||
await transformLegacy(asset, config, resolve, options); | ||
} else { | ||
await transformModern(asset, config, resolve, options); | ||
} | ||
return [asset]; | ||
@@ -108,92 +74,52 @@ }, | ||
function resolvePathImporter({asset, resolve, includePaths, options}) { | ||
// This is a reimplementation of the Sass resolution algorithm that uses Parcel's | ||
// FS and tracks all tried files so they are watched for creation. | ||
async function resolvePath( | ||
url, | ||
prev, | ||
): Promise<{filePath: string, contents: string, ...} | void> { | ||
/* | ||
Imports are resolved by trying, in order: | ||
* Loading a file relative to the file in which the `@import` appeared. | ||
* Each custom importer. | ||
* Loading a file relative to the current working directory (This rule doesn't really make sense for Parcel). | ||
* Each load path in `includePaths` | ||
* Each load path specified in the `SASS_PATH` environment variable, which should be semicolon-separated on Windows and colon-separated elsewhere. | ||
See: https://sass-lang.com/documentation/js-api#importer | ||
See also: https://github.com/sass/dart-sass/blob/006e6aa62f2417b5267ad5cdb5ba050226fab511/lib/src/importer/node/implementation.dart | ||
*/ | ||
let paths = [path.dirname(prev)]; | ||
if (includePaths) { | ||
paths.push(...includePaths); | ||
function detectVersion(config: any) { | ||
for (let legacyOption of [ | ||
'data', | ||
'indentType', | ||
'indentWidth', | ||
'linefeed', | ||
'outputStyle', | ||
'importer', | ||
'pkgImporter', | ||
'includePaths', | ||
'omitSourceMapUrl', | ||
'outFile', | ||
'sourceMapContents', | ||
'sourceMapEmbed', | ||
'sourceMapRoot', | ||
]) { | ||
if (config[legacyOption] != null) { | ||
return 'legacy'; | ||
} | ||
} | ||
asset.invalidateOnEnvChange('SASS_PATH'); | ||
if (options.env.SASS_PATH) { | ||
paths.push( | ||
...options.env.SASS_PATH.split( | ||
process.platform === 'win32' ? ';' : ':', | ||
).map(p => path.resolve(options.projectRoot, p)), | ||
); | ||
for (let modernOption of [ | ||
'loadPaths', | ||
'sourceMapIncludeSources', | ||
'style', | ||
'importers', | ||
]) { | ||
if (config[modernOption] != null) { | ||
return 'modern'; | ||
} | ||
} | ||
const urls = [url]; | ||
const urlFileName = path.basename(url); | ||
if (urlFileName[0] !== '_') { | ||
urls.push(path.join(path.dirname(url), `_${urlFileName}`)); | ||
} | ||
if (typeof config.sourceMap === 'string') { | ||
return 'legacy'; | ||
} | ||
if (url[0] !== '~') { | ||
for (let p of paths) { | ||
for (let u of urls) { | ||
const filePath = path.resolve(p, u); | ||
try { | ||
const contents = await asset.fs.readFile(filePath, 'utf8'); | ||
return { | ||
filePath, | ||
contents, | ||
}; | ||
} catch (err) { | ||
asset.invalidateOnFileCreate({filePath}); | ||
} | ||
} | ||
if ( | ||
config.functions && | ||
typeof config.functions === 'object' && | ||
Object.keys(config.functions).length > 0 | ||
) { | ||
for (let key in config.functions) { | ||
let fn = config.functions[key]; | ||
if (typeof fn === 'function' && fn.length > 1) { | ||
return 'legacy'; | ||
} | ||
} | ||
// If none of the default sass rules apply, try Parcel's resolver. | ||
for (let u of urls) { | ||
if (NODE_MODULE_ALIAS_RE.test(u)) { | ||
u = u.slice(1); | ||
} | ||
try { | ||
const filePath = await resolve(prev, u, { | ||
packageConditions: ['sass', 'style'], | ||
}); | ||
if (filePath) { | ||
const contents = await asset.fs.readFile(filePath, 'utf8'); | ||
return {filePath, contents}; | ||
} | ||
} catch (err) { | ||
continue; | ||
} | ||
} | ||
} | ||
return function (rawUrl, prev, done) { | ||
const url = rawUrl.replace(/^file:\/\//, ''); | ||
resolvePath(url, prev) | ||
.then(resolved => { | ||
if (resolved) { | ||
done({ | ||
file: resolved.filePath, | ||
contents: resolved.contents, | ||
}); | ||
} else { | ||
done(); | ||
} | ||
}) | ||
.catch(done); | ||
}; | ||
return 'modern'; | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
28748
8
830
2
5
11
2
214
Updatedsass@^1.79.4