Skip to content

Commit

Permalink
Merge pull request #324 from sass/merge
Browse files Browse the repository at this point in the history
Merge main into feature.color-4
  • Loading branch information
nex3 committed Aug 13, 2024
2 parents 3d9c234 + d2a3cbc commit 21c99cb
Show file tree
Hide file tree
Showing 61 changed files with 379 additions and 208 deletions.
14 changes: 14 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"extends": "./node_modules/gts/",
"rules": {
"@typescript-eslint/explicit-function-return-type": [
"error",
{"allowExpressions": true}
],
"func-style": ["error", "declaration"],
"prefer-const": ["error", {"destructuring": "all"}],
// It would be nice to sort import declaration order as well, but that's not
// autofixable and it's not worth the effort of handling manually.
"sort-imports": ["error", {"ignoreDeclarationSort": true}],
}
}
6 changes: 0 additions & 6 deletions .eslintrc.json

This file was deleted.

4 changes: 4 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ updates:
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
16 changes: 8 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 'lts/*'
check-latest: true
Expand All @@ -46,8 +46,8 @@ jobs:
fail-fast: false

steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
check-latest: true
Expand Down Expand Up @@ -89,10 +89,10 @@ jobs:
node_version: lts/-2

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: dart-lang/setup-dart@v1
with: {sdk: stable}
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with: {node-version: "${{ matrix.node_version }}"}

- name: Check out Dart Sass
Expand Down Expand Up @@ -140,8 +140,8 @@ jobs:
needs: [static_analysis, tests, sass_spec]

steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 'lts/*'
check-latest: true
Expand Down
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,39 @@
## 1.77.8

* No user-visible changes.

## 1.77.7

* Declarations that appear after nested rules are deprecated, because the
semantics Sass has historically used are different from the semantics
specified by CSS. In the future, Sass will adopt the standard CSS semantics.

See [the Sass website](https://sass-lang.com/d/mixed-decls) for details.

* **Potentially breaking bug fix:** `//` in certain places such as unknown
at-rule values was being preserved in the CSS output, leading to potentially
invalid CSS. It's now properly parsed as a silent comment and omitted from the
CSS output.

## 1.77.6

* Fix a few cases where comments and occasionally even whitespace wasn't allowed
between the end of Sass statements and the following semicolon.

## 1.77.5

* Fully trim redundant selectors generated by `@extend`.

## 1.77.4

### Embedded Sass

* Support passing `Version` input for `fatalDeprecations` as string over
embedded protocol.

* Fix a bug in the JS Embedded Host where `Version` could be incorrectly accepted
as input for `silenceDeprecations` and `futureDeprecations` in pure JS.

## 1.77.3

### Dart API
Expand Down
25 changes: 25 additions & 0 deletions bin/sass.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env node

import * as child_process from 'child_process';
import {compilerCommand} from '../lib/src/compiler-path';

// TODO npm/cmd-shim#152 and yarnpkg/berry#6422 - If and when the package
// managers support it, we should make this a proper shell script rather than a
// JS wrapper.

try {
child_process.execFileSync(
compilerCommand[0],
[...compilerCommand.slice(1), ...process.argv.slice(2)],
{
stdio: 'inherit',
windowsHide: true,
}
);
} catch (error) {
if (error.code) {
throw error;
} else {
process.exitCode = error.status;
}
}
21 changes: 15 additions & 6 deletions lib/src/compiler-path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,29 @@

import * as fs from 'fs';
import * as p from 'path';
import {getElfInterpreter} from './elf';
import {isErrnoException} from './utils';

/**
* Detect if the current running node binary is linked with musl libc by
* checking if the binary contains a string like "/.../ld-musl-$ARCH.so"
* Detect if the given binary is linked with musl libc by checking if
* the interpreter basename starts with "ld-musl-"
*/
const isLinuxMusl = function () {
return fs.readFileSync(process.execPath).includes('/ld-musl-');
};
function isLinuxMusl(path: string): boolean {
try {
const interpreter = getElfInterpreter(path);
return p.basename(interpreter).startsWith('ld-musl-');
} catch (error) {
console.warn(
`Warning: Failed to detect linux-musl, fallback to linux-gnu: ${error.message}`
);
return false;
}
}

/** The full command for the embedded compiler executable. */
export const compilerCommand = (() => {
const platform =
process.platform === 'linux' && isLinuxMusl()
process.platform === 'linux' && isLinuxMusl(process.execPath)
? 'linux-musl'
: (process.platform as string);

Expand Down
2 changes: 1 addition & 1 deletion lib/src/compiler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import * as compilerModule from './compiler/utils';
import {Compiler, initCompiler} from './compiler/sync';

const createDispatcher = jest.spyOn(compilerModule, 'createDispatcher');
function getIdHistory() {
function getIdHistory(): number[] {
return createDispatcher.mock.calls.map(([id]) => id);
}

Expand Down
2 changes: 1 addition & 1 deletion lib/src/compiler/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import * as p from 'path';
import * as supportsColor from 'supports-color';
import {deprecations, getDeprecationIds, Deprecation} from '../deprecations';
import {Deprecation, deprecations, getDeprecationIds} from '../deprecations';
import {deprotofySourceSpan} from '../deprotofy-span';
import {Dispatcher, DispatcherHandlers} from '../dispatcher';
import {Exception} from '../exception';
Expand Down
20 changes: 2 additions & 18 deletions lib/src/deprecations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,12 @@
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

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

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

/**
* Returns whether the given deprecation was active in the given 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;
if (version.major < deprecatedIn.major) return false;
if (version.minor > deprecatedIn.minor) return true;
if (version.minor < deprecatedIn.minor) return false;
return version.patch >= deprecatedIn.patch;
}

/**
* Converts a mixed array of deprecations, IDs, and versions to an array of IDs
* that's ready to include in a CompileRequest.
Expand All @@ -31,9 +17,7 @@ export function getDeprecationIds(
): string[] {
return arr.flatMap(item => {
if (item instanceof Version) {
return Object.values(deprecations)
.filter(deprecation => isActiveIn(deprecation, item))
.map(deprecation => deprecation.id);
return arr.map(item => item.toString());
} else if (typeof item === 'string') {
return item;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/src/dispatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {filter, map, mergeMap, takeUntil} from 'rxjs/operators';
import {OutboundResponse} from './messages';
import * as proto from './vendor/embedded_sass_pb';
import {RequestTracker} from './request-tracker';
import {PromiseOr, compilerError, thenOr, hostError} from './utils';
import {PromiseOr, compilerError, hostError, thenOr} from './utils';

// A callback that accepts a response or error.
type ResponseCallback = (
Expand Down
102 changes: 102 additions & 0 deletions lib/src/elf.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// 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.

import * as fs from 'fs';

/** Read a chunk of data from a file descriptor into a new Buffer. */
function readFileDescriptor(
fd: number,
position: number,
length: number
): Buffer {
const buffer = Buffer.alloc(length);
let offset = 0;
while (offset < length) {
const bytesRead = fs.readSync(fd, buffer, {
offset: offset,
position: position + offset,
});
if (bytesRead === 0) {
throw new Error(`failed to read fd ${fd}`);
}

offset += bytesRead;
}
return buffer;
}

/** Parse an ELF file and return its interpreter. */
export function getElfInterpreter(path: string): string {
const fd = fs.openSync(path, 'r');
try {
const elfIdentification = new DataView(
readFileDescriptor(fd, 0, 64).buffer
);

if (
elfIdentification.getUint8(0) !== 0x7f ||
elfIdentification.getUint8(1) !== 0x45 ||
elfIdentification.getUint8(2) !== 0x4c ||
elfIdentification.getUint8(3) !== 0x46
) {
throw new Error(`${path} is not an ELF file.`);
}

const elfIdentificationClass = elfIdentification.getUint8(4);
if (elfIdentificationClass !== 1 && elfIdentificationClass !== 2) {
throw new Error(`${path} has an invalid ELF class.`);
}
const elfClass32 = elfIdentificationClass === 1;

const elfIdentificationData = elfIdentification.getUint8(5);
if (elfIdentificationData !== 1 && elfIdentificationData !== 2) {
throw new Error(`${path} has an invalid endianness.`);
}
const littleEndian = elfIdentificationData === 1;

// Converting BigUint64 to Number because node Buffer length has to be
// number type, and we don't expect any elf we check with this method to
// be larger than 9007199254740991 bytes.
const programHeadersOffset = elfClass32
? elfIdentification.getUint32(28, littleEndian)
: Number(elfIdentification.getBigUint64(32, littleEndian));
const programHeadersEntrySize = elfClass32
? elfIdentification.getUint16(42, littleEndian)
: elfIdentification.getUint16(54, littleEndian);
const programHeadersEntryCount = elfClass32
? elfIdentification.getUint16(44, littleEndian)
: elfIdentification.getUint16(56, littleEndian);

const programHeaders = new DataView(
readFileDescriptor(
fd,
programHeadersOffset,
programHeadersEntrySize * programHeadersEntryCount
).buffer
);
for (let i = 0; i < programHeadersEntryCount; i++) {
const byteOffset = i * programHeadersEntrySize;
const segmentType = programHeaders.getUint32(byteOffset, littleEndian);
if (segmentType !== 3) continue; // 3 is PT_INTERP, the interpreter

const segmentOffset = elfClass32
? programHeaders.getUint32(byteOffset + 4, littleEndian)
: Number(programHeaders.getBigUint64(byteOffset + 8, littleEndian));
const segmentFileSize = elfClass32
? programHeaders.getUint32(byteOffset + 16, littleEndian)
: Number(programHeaders.getBigUint64(byteOffset + 32, littleEndian));

const buffer = readFileDescriptor(fd, segmentOffset, segmentFileSize);
if (buffer[segmentFileSize - 1] !== 0) {
throw new Error(`${path} is corrupted.`);
}

return buffer.toString('utf8', 0, segmentFileSize - 1);
}

throw new Error(`${path} does not contain an interpreter entry.`);
} finally {
fs.closeSync(fd);
}
}
2 changes: 1 addition & 1 deletion lib/src/exception.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export class Exception extends Error implements SassException {
this.span = deprotofySourceSpan(failure.span!);
}

toString() {
toString(): string {
return this.message;
}
}
2 changes: 1 addition & 1 deletion lib/src/importer-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ 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';
import {catchOr, thenOr, PromiseOr} from './utils';
import {PromiseOr, catchOr, thenOr} from './utils';

const entryPointDirectoryKey = Symbol();

Expand Down
6 changes: 3 additions & 3 deletions lib/src/legacy/importer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import * as util from 'util';

import {resolvePath} from './resolve-path';
import {
PromiseOr,
SyncBoolean,
fileUrlToPathCrossPlatform,
isErrnoException,
thenOr,
PromiseOr,
SyncBoolean,
} from '../utils';
import {
Importer,
Expand All @@ -26,10 +26,10 @@ import {
LegacySyncImporter,
} from '../vendor/sass';
import {
pathToLegacyFileUrl,
legacyFileUrlToPath,
legacyImporterProtocol,
legacyImporterProtocolPrefix,
pathToLegacyFileUrl,
} from './utils';

/**
Expand Down
Loading

0 comments on commit 21c99cb

Please sign in to comment.