Skip to content

Commit

Permalink
Merge pull request #302 from sass/merge-main
Browse files Browse the repository at this point in the history
Merge origin/main into feature.color-4
  • Loading branch information
nex3 committed May 30, 2024
2 parents 7d44ff3 + 07af8d6 commit 3d9c234
Show file tree
Hide file tree
Showing 29 changed files with 283 additions and 210 deletions.
48 changes: 48 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,51 @@
## 1.77.3

### Dart API

* `Deprecation.duplicateVariableFlags` has been deprecated and replaced with
`Deprecation.duplicateVarFlags` to make it consistent with the
`duplicate-var-flags` name used on the command line and in the JS API.

## 1.77.2

* Don't emit deprecation warnings for functions and mixins beginning with `__`.

* Allow user-defined functions whose names begin with `_` and otherwise look
like vendor-prefixed functions with special CSS syntax.

### Command-Line Interface

* Properly handle the `--silence-deprecation` flag.

* Handle the `--fatal-deprecation` and `--future-deprecation` flags for
`--interactive` mode.

## 1.77.1

* Fix a crash that could come up with importers in certain contexts.

## 1.77.0

* *Don't* throw errors for at-rules in keyframe blocks.

## 1.76.0

* Throw errors for misplaced statements in keyframe blocks.

* Mixins and functions whose names begin with `--` are now deprecated for
forwards-compatibility with the in-progress CSS functions and mixins spec.
This deprecation is named `css-function-mixin`.

## 1.75.0

* Fix a bug in which stylesheet canonicalization could be cached incorrectly
when custom importers or the Node.js package importer made decisions based on
the URL of the containing stylesheet.

### JS API

* Allow `importer` to be passed without `url` in `StringOptionsWithImporter`.

## 1.74.1

* No user-visible changes.
Expand Down
2 changes: 1 addition & 1 deletion lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ export {
Deprecation,
DeprecationOrId,
DeprecationStatus,
Version,
} from './src/deprecations';
export {Version} from './src/version';
export {render, renderSync} from './src/legacy';

export const info = `sass-embedded\t${pkg.version}`;
Expand Down
32 changes: 32 additions & 0 deletions lib/src/canonicalize-context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2024 Google LLC. Use of this source code is governed by an
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

export class CanonicalizeContext {
readonly fromImport: boolean;

private readonly _containingUrl: URL | null;

get containingUrl(): URL | null {
this._containingUrlAccessed = true;
return this._containingUrl;
}

private _containingUrlAccessed = false;

/**
* Whether the `containingUrl` getter has been accessed.
*
* This is marked as public so that the importer registry can access it, but
* it's not part of the package's public API and should not be accessed by
* user code. It may be renamed or removed without warning in the future.
*/
get containingUrlAccessed(): boolean {
return this._containingUrlAccessed;
}

constructor(containingUrl: URL | null, fromImport: boolean) {
this._containingUrl = containingUrl;
this.fromImport = fromImport;
}
}
157 changes: 6 additions & 151 deletions lib/src/deprecations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,17 @@
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

import * as api from './vendor/sass';
import {deprecations} from './vendor/deprecations';
import {Deprecation, DeprecationOrId} from './vendor/sass';
import {Version} from './version';

export {deprecations} from './vendor/deprecations';
export {Deprecation, DeprecationOrId, DeprecationStatus} from './vendor/sass';

export class Version implements api.Version {
constructor(
readonly major: number,
readonly minor: number,
readonly patch: number
) {}
static parse(version: string): Version {
const match = version.match(/^(\d+)\.(\d+)\.(\d+)$/);
if (match === null) {
throw new Error(`Invalid version ${version}`);
}
return new Version(
parseInt(match[1]),
parseInt(match[2]),
parseInt(match[3])
);
}
}

/**
* Returns whether the given deprecation was active in the given version.
*/
function isActiveIn(deprecation: api.Deprecation, version: Version) {
function isActiveIn(deprecation: Deprecation, version: Version) {
const deprecatedIn = deprecation.deprecatedIn;
if (deprecation.status !== 'active' || !deprecatedIn) return false;
if (version.major > deprecatedIn.major) return true;
Expand All @@ -43,7 +27,7 @@ function isActiveIn(deprecation: api.Deprecation, version: Version) {
* that's ready to include in a CompileRequest.
*/
export function getDeprecationIds(
arr: (api.DeprecationOrId | Version)[]
arr: (DeprecationOrId | Version)[]
): string[] {
return arr.flatMap(item => {
if (item instanceof Version) {
Expand All @@ -56,132 +40,3 @@ export function getDeprecationIds(
return item.id;
});
}

export const deprecations: typeof api.deprecations = {
'call-string': {
id: 'call-string',
status: 'active',
deprecatedIn: new Version(0, 0, 0),
obsoleteIn: null,
description: 'Passing a string directly to meta.call().',
},
elseif: {
id: 'elseif',
status: 'active',
deprecatedIn: new Version(1, 3, 2),
obsoleteIn: null,
description: '@elseif.',
},
'moz-document': {
id: 'moz-document',
status: 'active',
deprecatedIn: new Version(1, 7, 2),
obsoleteIn: null,
description: '@-moz-document.',
},
'relative-canonical': {
id: 'relative-canonical',
status: 'active',
deprecatedIn: new Version(1, 14, 2),
obsoleteIn: null,
},
'new-global': {
id: 'new-global',
status: 'active',
deprecatedIn: new Version(1, 17, 2),
obsoleteIn: null,
description: 'Declaring new variables with !global.',
},
'color-module-compat': {
id: 'color-module-compat',
status: 'active',
deprecatedIn: new Version(1, 23, 0),
obsoleteIn: null,
description:
'Using color module functions in place of plain CSS functions.',
},
'slash-div': {
id: 'slash-div',
status: 'active',
deprecatedIn: new Version(1, 33, 0),
obsoleteIn: null,
description: '/ operator for division.',
},
'bogus-combinators': {
id: 'bogus-combinators',
status: 'active',
deprecatedIn: new Version(1, 54, 0),
obsoleteIn: null,
description: 'Leading, trailing, and repeated combinators.',
},
'strict-unary': {
id: 'strict-unary',
status: 'active',
deprecatedIn: new Version(1, 55, 0),
obsoleteIn: null,
description: 'Ambiguous + and - operators.',
},
'function-units': {
id: 'function-units',
status: 'active',
deprecatedIn: new Version(1, 56, 0),
obsoleteIn: null,
description: 'Passing invalid units to built-in functions.',
},
'duplicate-var-flags': {
id: 'duplicate-var-flags',
status: 'active',
deprecatedIn: new Version(1, 62, 0),
obsoleteIn: null,
description: 'Using !default or !global multiple times for one variable.',
},
'null-alpha': {
id: 'null-alpha',
status: 'active',
deprecatedIn: new Version(1, 62, 3),
obsoleteIn: null,
description: 'Passing null as alpha in the JS API.',
},
'abs-percent': {
id: 'abs-percent',
status: 'active',
deprecatedIn: new Version(1, 65, 0),
obsoleteIn: null,
description: 'Passing percentages to the Sass abs() function.',
},
'fs-importer-cwd': {
id: 'fs-importer-cwd',
status: 'active',
deprecatedIn: new Version(1, 73, 0),
obsoleteIn: null,
description:
'Using the current working directory as an implicit load path.',
},
'color-4-api': {
id: 'color-4-api',
status: 'active',
deprecatedIn: new Version(1, 76, 0),
obsoleteIn: null,
description: 'Methods of interacting with legacy SassColors.',
},
'color-functions': {
id: 'color-functions',
status: 'active',
deprecatedIn: new Version(1, 76, 0),
obsoleteIn: null,
description: 'Using global Sass color functions.',
},
import: {
id: 'import',
status: 'future',
deprecatedIn: null,
obsoleteIn: null,
description: '@import rules.',
},
'user-authored': {
id: 'user-authored',
status: 'user',
deprecatedIn: null,
obsoleteIn: null,
},
};
33 changes: 20 additions & 13 deletions lib/src/importer-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import * as p from 'path';
import {URL} from 'url';
import {inspect} from 'util';

import {CanonicalizeContext} from './canonicalize-context';
import * as utils from './utils';
import {FileImporter, Importer, Options} from './vendor/sass';
import * as proto from './vendor/embedded_sass_pb';
Expand Down Expand Up @@ -115,21 +116,22 @@ export class ImporterRegistry<sync extends 'sync' | 'async'> {
throw utils.compilerError('Unknown CanonicalizeRequest.importer_id');
}

const canonicalizeContext = new CanonicalizeContext(
request.containingUrl ? new URL(request.containingUrl) : null,
request.fromImport
);

return catchOr(
() => {
return thenOr(
importer.canonicalize(request.url, {
fromImport: request.fromImport,
containingUrl: request.containingUrl
? new URL(request.containingUrl)
: null,
}),
importer.canonicalize(request.url, canonicalizeContext),
url =>
new proto.InboundMessage_CanonicalizeResponse({
result:
url === null
? {case: undefined}
: {case: 'url', value: url.toString()},
containingUrlUnused: !canonicalizeContext.containingUrlAccessed,
})
);
},
Expand Down Expand Up @@ -197,17 +199,21 @@ export class ImporterRegistry<sync extends 'sync' | 'async'> {
throw utils.compilerError('Unknown FileImportRequest.importer_id');
}

const canonicalizeContext = new CanonicalizeContext(
request.containingUrl ? new URL(request.containingUrl) : null,
request.fromImport
);

return catchOr(
() => {
return thenOr(
importer.findFileUrl(request.url, {
fromImport: request.fromImport,
containingUrl: request.containingUrl
? new URL(request.containingUrl)
: null,
}),
importer.findFileUrl(request.url, canonicalizeContext),
url => {
if (!url) return new proto.InboundMessage_FileImportResponse();
if (!url) {
return new proto.InboundMessage_FileImportResponse({
containingUrlUnused: !canonicalizeContext.containingUrlAccessed,
});
}
if (url.protocol !== 'file:') {
throw (
`FileImporter ${inspect(importer)} returned non-file: URL ` +
Expand All @@ -216,6 +222,7 @@ export class ImporterRegistry<sync extends 'sync' | 'async'> {
}
return new proto.InboundMessage_FileImportResponse({
result: {case: 'fileUrl', value: url.toString()},
containingUrlUnused: !canonicalizeContext.containingUrlAccessed,
});
}
);
Expand Down
26 changes: 25 additions & 1 deletion lib/src/legacy/importer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,34 @@ export class LegacyImporterWrapper<sync extends 'sync' | 'async'>

canonicalize(
url: string,
options: {fromImport: boolean}
options: {fromImport: boolean; containingUrl: URL | null}
): PromiseOr<URL | null, sync> {
if (url.startsWith(endOfLoadProtocol)) return new URL(url);

// Emulate a base importer instead of using a real base importer,
// because we want to mark containingUrl as used, which is impossible
// in a real base importer.
if (options.containingUrl !== null) {
try {
const absoluteUrl = new URL(url, options.containingUrl).toString();
const resolved = this.canonicalize(absoluteUrl, {
fromImport: options.fromImport,
containingUrl: null,
});
if (resolved !== null) return resolved;
} catch (error: unknown) {
if (
error instanceof TypeError &&
isErrnoException(error) &&
error.code === 'ERR_INVALID_URL'
) {
// ignore
} else {
throw error;
}
}
}

if (
url.startsWith(legacyImporterProtocolPrefix) ||
url.startsWith(legacyImporterProtocol)
Expand Down
Loading

0 comments on commit 3d9c234

Please sign in to comment.