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 support for SassCalculation #237

Merged
merged 14 commits into from
Jul 19, 2023
20 changes: 20 additions & 0 deletions lib/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ export const compileAsync = sass.compileAsync;
export const compileString = sass.compileString;
export const compileStringAsync = sass.compileStringAsync;
export const Logger = sass.Logger;
export const CalculationInterpolation = sass.CalculationInterpolation
export const CalculationOperation = sass.CalculationOperation
export const CalculationOperator = sass.CalculationOperator
export const SassArgumentList = sass.SassArgumentList;
export const SassBoolean = sass.SassBoolean;
export const SassCalculation = sass.SassCalculation
export const SassColor = sass.SassColor;
export const SassFunction = sass.SassFunction;
export const SassList = sass.SassList;
Expand Down Expand Up @@ -59,6 +63,18 @@ export default {
defaultExportDeprecation();
return sass.Logger;
},
get CalculationOperation() {
defaultExportDeprecation();
return sass.CalculationOperation;
},
get CalculationOperator() {
defaultExportDeprecation();
return sass.CalculationOperator;
},
get CalculationInterpolation() {
defaultExportDeprecation();
return sass.CalculationInterpolation;
},
get SassArgumentList() {
defaultExportDeprecation();
return sass.SassArgumentList;
Expand All @@ -67,6 +83,10 @@ export default {
defaultExportDeprecation();
return sass.SassBoolean;
},
get SassCalculation() {
defaultExportDeprecation();
return sass.SassCalculation;
},
get SassColor() {
defaultExportDeprecation();
return sass.SassColor;
Expand Down
6 changes: 6 additions & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ export {SassNumber} from './src/value/number';
export {SassString} from './src/value/string';
export {Value} from './src/value';
export {sassNull} from './src/value/null';
export {
CalculationOperation,
CalculationOperator,
CalculationInterpolation,
SassCalculation,
} from './src/value/calculations';

export * as types from './src/legacy/value';
export {Exception} from './src/exception';
Expand Down
202 changes: 192 additions & 10 deletions lib/src/protofier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ import {SassString} from './value/string';
import {Value} from './value';
import {sassNull} from './value/null';
import {sassTrue, sassFalse} from './value/boolean';
import {
CalculationValue,
SassCalculation,
CalculationInterpolation,
CalculationOperation,
CalculationOperator,
} from './value/calculations';

/**
* A class that converts [Value] objects into protobufs.
Expand Down Expand Up @@ -56,11 +63,7 @@ export class Protofier {
string.quoted = value.hasQuotes;
result.value = {case: 'string', value: string};
} else if (value instanceof SassNumber) {
const number = new proto.Value_Number();
number.value = value.value;
number.numerators = value.numeratorUnits.toArray();
number.denominators = value.denominatorUnits.toArray();
result.value = {case: 'number', value: number};
result.value = {case: 'number', value: this.protofyNumber(value)};
} else if (value instanceof SassColor) {
if (value.hasCalculatedHsl) {
const color = new proto.Value_HslColor();
Expand Down Expand Up @@ -116,6 +119,11 @@ export class Protofier {
fn.signature = value.signature!;
result.value = {case: 'hostFunction', value: fn};
}
} else if (value instanceof SassCalculation) {
result.value = {
case: 'calculation',
value: this.protofyCalculation(value),
};
} else if (value === sassTrue) {
result.value = {case: 'singleton', value: proto.SingletonValue.TRUE};
} else if (value === sassFalse) {
Expand All @@ -128,6 +136,15 @@ export class Protofier {
return result;
}

/** Converts `number` to its protocol buffer representation. */
private protofyNumber(number: SassNumber): proto.Value_Number {
return new proto.Value_Number({
value: number.value,
numerators: number.numeratorUnits.toArray(),
denominators: number.denominatorUnits.toArray(),
});
}

/** Converts `separator` to its protocol buffer representation. */
private protofySeparator(separator: ListSeparator): proto.ListSeparator {
switch (separator) {
Expand All @@ -144,6 +161,68 @@ export class Protofier {
}
}

/** Converts `calculation` to its protocol buffer representation. */
private protofyCalculation(
calculation: SassCalculation
): proto.Value_Calculation {
return new proto.Value_Calculation({
name: calculation.name,
arguments: calculation.arguments
.map(this.protofyCalculationValue.bind(this))
.toArray(),
});
}

/** Converts a CalculationValue that appears within a `SassCalculation` to
* its protocol buffer representation. */
private protofyCalculationValue(
value: Object
): proto.Value_Calculation_CalculationValue {
const result = new proto.Value_Calculation_CalculationValue();
if (value instanceof SassCalculation) {
result.value = {
case: 'calculation',
value: this.protofyCalculation(value),
};
} else if (value instanceof CalculationOperation) {
result.value = {
case: 'operation',
value: new proto.Value_Calculation_CalculationOperation({
operator: this.protofyCalculationOperator(value.operator),
left: this.protofyCalculationValue(value.left),
right: this.protofyCalculationValue(value.right),
}),
};
} else if (value instanceof CalculationInterpolation) {
result.value = {case: 'interpolation', value: value.value};
} else if (value instanceof SassString) {
result.value = {case: 'string', value: value.text};
} else if (value instanceof SassNumber) {
result.value = {case: 'number', value: this.protofyNumber(value)};
} else {
throw utils.compilerError(`Unknown CalculationValue ${value}`);
}
return result;
}

/** Converts `operator` to its protocol buffer representation. */
private protofyCalculationOperator(
operator: CalculationOperator
): proto.CalculationOperator {
switch (operator) {
case '+':
return proto.CalculationOperator.PLUS;
case '-':
return proto.CalculationOperator.MINUS;
case '*':
return proto.CalculationOperator.TIMES;
case '/':
return proto.CalculationOperator.DIVIDE;
default:
throw utils.compilerError(`Unknown CalculationOperator ${operator}`);
}
}

/** Converts `value` to its JS representation. */
deprotofy(value: proto.Value): Value {
switch (value.value.case) {
Expand All @@ -155,11 +234,7 @@ export class Protofier {
}

case 'number': {
const number = value.value.value;
return new SassNumber(number.value, {
numeratorUnits: number.numerators,
denominatorUnits: number.denominators,
});
return this.deprotofyNumber(value.value.value);
}

case 'rgbColor': {
Expand Down Expand Up @@ -247,6 +322,9 @@ export class Protofier {
'The compiler may not send Value.host_function.'
);

case 'calculation':
return this.deprotofyCalculation(value.value.value);

case 'singleton':
switch (value.value.value) {
case proto.SingletonValue.TRUE:
Expand All @@ -263,6 +341,14 @@ export class Protofier {
}
}

/** Converts `number` to its JS representation. */
private deprotofyNumber(number: proto.Value_Number): SassNumber {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a short doc comment for this.

return new SassNumber(number.value, {
numeratorUnits: number.numerators,
denominatorUnits: number.denominators,
});
}

/** Converts `separator` to its JS representation. */
private deprotofySeparator(separator: proto.ListSeparator): ListSeparator {
switch (separator) {
Expand All @@ -278,4 +364,100 @@ export class Protofier {
throw utils.compilerError(`Unknown separator ${separator}`);
}
}

/** Converts `calculation` to its Sass representation. */
private deprotofyCalculation(
calculation: proto.Value_Calculation
): SassCalculation {
switch (calculation.name) {
case 'calc':
if (calculation.arguments.length !== 1) {
throw utils.compilerError(
'Value.Calculation.arguments must have exactly one argument for calc().'
);
}
return SassCalculation.calc(
this.deprotofyCalculationValue(calculation.arguments[0])
);
case 'clamp':
if (calculation.arguments.length !== 3) {
throw utils.compilerError(
'Value.Calculation.arguments must have exactly 3 arguments for clamp().'
);
}
return SassCalculation.clamp(
this.deprotofyCalculationValue(calculation.arguments[0]),
this.deprotofyCalculationValue(calculation.arguments[1]),
this.deprotofyCalculationValue(calculation.arguments[2])
);
case 'min':
if (calculation.arguments.length === 0) {
throw utils.compilerError(
'Value.Calculation.arguments must have at least 1 argument for min().'
);
}
return SassCalculation.min(
calculation.arguments.map(this.deprotofyCalculationValue)
);
case 'max':
if (calculation.arguments.length === 0) {
throw utils.compilerError(
'Value.Calculation.arguments must have at least 1 argument for max().'
);
}
return SassCalculation.max(
calculation.arguments.map(this.deprotofyCalculationValue)
);
default:
throw utils.compilerError(
`Value.Calculation.name "${calculation.name}" is not a recognized calculation type.`
);
}
}

/** Converts `value` to its Sass representation. */
private deprotofyCalculationValue(
value: proto.Value_Calculation_CalculationValue
): CalculationValue {
switch (value.value.case) {
case 'number':
return this.deprotofyNumber(value.value.value);
case 'calculation':
return this.deprotofyCalculation(value.value.value);
case 'string':
return new SassString(value.value.value, {quotes: false});
case 'operation':
return new CalculationOperation(
this.deprotofyCalculationOperator(value.value.value.operator),
this.deprotofyCalculationValue(
value.value.value.left as proto.Value_Calculation_CalculationValue
),
this.deprotofyCalculationValue(
value.value.value.right as proto.Value_Calculation_CalculationValue
)
);
case 'interpolation':
return new CalculationInterpolation(value.value.value);
default:
throw utils.mandatoryError('Calculation.CalculationValue.value');
}
}

/** Converts `operator` to its Sass representation. */
private deprotofyCalculationOperator(
operator: proto.CalculationOperator
): CalculationOperator {
switch (operator) {
case proto.CalculationOperator.PLUS:
return '+';
case proto.CalculationOperator.MINUS:
return '-';
case proto.CalculationOperator.TIMES:
return '*';
case proto.CalculationOperator.DIVIDE:
return '/';
default:
throw utils.compilerError(`Unknown CalculationOperator ${operator}`);
}
}
}
Loading
Loading