Skip to content

Commit

Permalink
Add proto logic for calculations
Browse files Browse the repository at this point in the history
  • Loading branch information
jerivas committed Jul 17, 2023
1 parent ba077ee commit ced9d56
Show file tree
Hide file tree
Showing 2 changed files with 180 additions and 7 deletions.
12 changes: 5 additions & 7 deletions lib/src/function-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,15 +158,13 @@ function simplify(value: unknown): unknown {
if (value.name === 'max') {
return SassCalculation.max(simplifiedArgs);
}
throw new Error(`Unknown calculation function: ${value.name}`);
throw new Error(`Unknown calculation function: ${value.name}.`);
}
if (value instanceof CalculationOperation) {
return simplify(
new CalculationOperation(
value.operator,
simplify(value.left) as CalculationValue,
simplify(value.right) as CalculationValue
)
return new CalculationOperation(
value.operator,
simplify(value.left) as CalculationValue,
simplify(value.right) as CalculationValue
);
}
return value;
Expand Down
175 changes: 175 additions & 0 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 @@ -116,6 +123,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 Down Expand Up @@ -144,6 +156,69 @@ 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 {
var result = new proto.Value_Calculation_CalculationValue();

Check failure on line 176 in lib/src/protofier.ts

View workflow job for this annotation

GitHub Actions / Static analysis

Unexpected var, use let or const instead
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) {
// @ts-ignore

Check failure on line 196 in lib/src/protofier.ts

View workflow job for this annotation

GitHub Actions / Static analysis

Do not use "@ts-ignore" because it alters compilation errors
result.value = this.protofy(value).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 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 Down Expand Up @@ -278,4 +356,101 @@ 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) {

Check failure on line 366 in lib/src/protofier.ts

View workflow job for this annotation

GitHub Actions / Static analysis

Expected '!==' and instead saw '!='
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) {

Check failure on line 375 in lib/src/protofier.ts

View workflow job for this annotation

GitHub Actions / Static analysis

Expected '!==' and instead saw '!='
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':
// @ts-ignore

Check failure on line 416 in lib/src/protofier.ts

View workflow job for this annotation

GitHub Actions / Static analysis

Do not use "@ts-ignore" because it alters compilation errors
return this.deprotofy(value) as SassNumber;
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}`);
}
}
}

0 comments on commit ced9d56

Please sign in to comment.