mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-29 07:16:36 +01:00
95c37e1ba3
* feat: add yaml feature management Add yaml feature file per build type. Also add method to parse yaml and set enabled features env to true. The build process will then replace any process.env[feature] that exists on the config by its value * chore: add example for desktop * Added initial draft of build features * [TMP] Sync between computers * Is able to succesfully build stable extension with snaps feature * Removing var context from builds.yml * Add asssets to builds.yml * Minor bug fixes and removing debug logs * [WIP] Test changes * Removed TODOs * Fix regession bug Also * remove debug logs * merge Variables.set and Variables.setMany with an overload * Fix build, lint and a bunch of issues * Update LavaMoat policies * Re-add desktop build type * Fix some tests * Fix desktop build * Define some env variables used by MV3 * Fix lint * Fix remove-fenced-code tests * Fix README typo * Move new code * Fix missing asset copy * Move Jest env setup * Fix path for test after rebase * Fix code fences * Fix fencing and LavaMoat policies * Fix MMI code-fencing after rebase * Fix MMI code fencing after merge * Fix more MMI code fencing --------- Co-authored-by: cryptotavares <joao.tavares@consensys.net> Co-authored-by: Frederik Bolding <frederik.bolding@gmail.com> Co-authored-by: Brad Decker <bhdecker84@gmail.com>
1062 lines
28 KiB
JavaScript
1062 lines
28 KiB
JavaScript
const deepFreeze = require('deep-freeze-strict');
|
|
const { loadBuildTypesConfig } = require('../../lib/build-type');
|
|
const {
|
|
createRemoveFencedCodeTransform,
|
|
removeFencedCode,
|
|
} = require('./remove-fenced-code');
|
|
const transformUtils = require('./utils');
|
|
|
|
jest.mock('./utils', () => ({
|
|
lintTransformedFile: jest.fn(),
|
|
}));
|
|
|
|
// The test data is just strings. We get it from a function at the end of this
|
|
// file because it takes up a lot of lines and is very distracting.
|
|
const testData = getTestData();
|
|
|
|
const MAIN_BUILD = 'build-main';
|
|
const FLASK_BUILD = 'build-flask';
|
|
|
|
const getMinimalFencedCode = (params = FLASK_BUILD) =>
|
|
`///: BEGIN:ONLY_INCLUDE_IN(${params})
|
|
Conditionally_Included
|
|
///: END:ONLY_INCLUDE_IN
|
|
`;
|
|
|
|
const getFeatures = ({ all, active }) => ({
|
|
all: new Set(all),
|
|
active: new Set(active),
|
|
});
|
|
|
|
const buildTypesConfig = loadBuildTypesConfig();
|
|
|
|
describe('build/transforms/remove-fenced-code', () => {
|
|
describe('createRemoveFencedCodeTransform', () => {
|
|
const { lintTransformedFile: lintTransformedFileMock } = transformUtils;
|
|
const mockJsFileName = 'file.js';
|
|
|
|
beforeEach(() => {
|
|
lintTransformedFileMock.mockImplementation(() => Promise.resolve());
|
|
});
|
|
|
|
it('returns a PassThrough stream for files with ignored extensions', async () => {
|
|
const fileContent = '"Valid JSON content"\n';
|
|
const stream = createRemoveFencedCodeTransform(
|
|
getFeatures({
|
|
active: [MAIN_BUILD],
|
|
all: [MAIN_BUILD],
|
|
}),
|
|
)('file.json');
|
|
let streamOutput = '';
|
|
|
|
await new Promise((resolve) => {
|
|
stream.on('data', (data) => {
|
|
streamOutput = streamOutput.concat(data.toString('utf8'));
|
|
});
|
|
|
|
stream.on('end', () => {
|
|
expect(streamOutput).toStrictEqual(fileContent);
|
|
expect(lintTransformedFileMock).not.toHaveBeenCalled();
|
|
resolve();
|
|
});
|
|
|
|
stream.write(Buffer.from(fileContent));
|
|
setTimeout(() => stream.end());
|
|
});
|
|
});
|
|
|
|
it('transforms a file read as a single chunk', async () => {
|
|
const filePrefix = '// A comment\n';
|
|
const fileContent = filePrefix.concat(getMinimalFencedCode());
|
|
|
|
const stream = createRemoveFencedCodeTransform(
|
|
getFeatures({
|
|
active: [MAIN_BUILD],
|
|
all: [MAIN_BUILD, FLASK_BUILD],
|
|
}),
|
|
)(mockJsFileName);
|
|
let streamOutput = '';
|
|
|
|
await new Promise((resolve) => {
|
|
stream.on('data', (data) => {
|
|
streamOutput = streamOutput.concat(data.toString('utf8'));
|
|
});
|
|
|
|
stream.on('end', () => {
|
|
expect(streamOutput).toStrictEqual(filePrefix);
|
|
expect(lintTransformedFileMock).toHaveBeenCalledTimes(1);
|
|
expect(lintTransformedFileMock).toHaveBeenCalledWith(
|
|
filePrefix,
|
|
mockJsFileName,
|
|
);
|
|
resolve();
|
|
});
|
|
|
|
stream.end(fileContent);
|
|
});
|
|
});
|
|
|
|
it('transforms a file read as multiple chunks', async () => {
|
|
const filePrefix = '// A comment\n';
|
|
const chunks = filePrefix
|
|
.concat(getMinimalFencedCode())
|
|
.split('\n')
|
|
// The final element in the split array is the empty string, which is
|
|
// useful for calling .join, but undesirable here.
|
|
.filter((line) => line !== '')
|
|
.map((line) => `${line}\n`);
|
|
|
|
const stream = createRemoveFencedCodeTransform(
|
|
getFeatures({
|
|
active: [MAIN_BUILD],
|
|
all: [MAIN_BUILD, FLASK_BUILD],
|
|
}),
|
|
)(mockJsFileName);
|
|
let streamOutput = '';
|
|
|
|
await new Promise((resolve) => {
|
|
stream.on('data', (data) => {
|
|
streamOutput = streamOutput.concat(data.toString('utf8'));
|
|
});
|
|
|
|
stream.on('end', () => {
|
|
expect(streamOutput).toStrictEqual(filePrefix);
|
|
expect(lintTransformedFileMock).toHaveBeenCalledTimes(1);
|
|
expect(lintTransformedFileMock).toHaveBeenCalledWith(
|
|
filePrefix,
|
|
mockJsFileName,
|
|
);
|
|
resolve();
|
|
});
|
|
|
|
chunks.forEach((chunk) => stream.write(chunk));
|
|
setTimeout(() => stream.end());
|
|
});
|
|
});
|
|
|
|
it('handles file with fences that is unmodified by the transform', async () => {
|
|
const fileContent = getMinimalFencedCode(MAIN_BUILD);
|
|
|
|
const stream = createRemoveFencedCodeTransform(
|
|
getFeatures({
|
|
active: [MAIN_BUILD],
|
|
all: [MAIN_BUILD],
|
|
}),
|
|
)(mockJsFileName);
|
|
let streamOutput = '';
|
|
|
|
await new Promise((resolve) => {
|
|
stream.on('data', (data) => {
|
|
streamOutput = streamOutput.concat(data.toString('utf8'));
|
|
});
|
|
|
|
stream.on('end', () => {
|
|
expect(streamOutput).toStrictEqual(fileContent);
|
|
expect(lintTransformedFileMock).not.toHaveBeenCalled();
|
|
resolve();
|
|
});
|
|
|
|
stream.end(fileContent);
|
|
});
|
|
});
|
|
|
|
it('skips linting for transformed file if shouldLintTransformedFiles is false', async () => {
|
|
const filePrefix = '// A comment\n';
|
|
const fileContent = filePrefix.concat(getMinimalFencedCode());
|
|
|
|
const stream = createRemoveFencedCodeTransform(
|
|
getFeatures({ all: [MAIN_BUILD, FLASK_BUILD], active: [MAIN_BUILD] }),
|
|
false,
|
|
)(mockJsFileName);
|
|
let streamOutput = '';
|
|
|
|
await new Promise((resolve) => {
|
|
stream.on('data', (data) => {
|
|
streamOutput = streamOutput.concat(data.toString('utf8'));
|
|
});
|
|
|
|
stream.on('end', () => {
|
|
expect(streamOutput).toStrictEqual(filePrefix);
|
|
expect(lintTransformedFileMock).not.toHaveBeenCalled();
|
|
resolve();
|
|
});
|
|
|
|
stream.end(fileContent);
|
|
});
|
|
});
|
|
|
|
it('handles error during code fence removal or parsing', async () => {
|
|
const fileContent = getMinimalFencedCode().concat(
|
|
'///: END:ONLY_INCLUDE_IN',
|
|
);
|
|
|
|
const stream = createRemoveFencedCodeTransform(
|
|
getFeatures({ all: [MAIN_BUILD, FLASK_BUILD], active: [MAIN_BUILD] }),
|
|
)(mockJsFileName);
|
|
|
|
await new Promise((resolve) => {
|
|
stream.on('error', (error) => {
|
|
expect(error.message).toStrictEqual(
|
|
expect.stringContaining(
|
|
'A valid fence consists of two fence lines, but the file contains an uneven number, "3", of fence lines.',
|
|
),
|
|
);
|
|
expect(lintTransformedFileMock).toHaveBeenCalledTimes(0);
|
|
resolve();
|
|
});
|
|
|
|
stream.end(fileContent);
|
|
});
|
|
});
|
|
|
|
it('handles transformed file lint failure', async () => {
|
|
lintTransformedFileMock.mockImplementationOnce(() =>
|
|
Promise.reject(new Error('lint failure')),
|
|
);
|
|
|
|
const filePrefix = '// A comment\n';
|
|
const fileContent = filePrefix.concat(getMinimalFencedCode());
|
|
|
|
const stream = createRemoveFencedCodeTransform(
|
|
getFeatures({ all: [FLASK_BUILD], active: [] }),
|
|
)(mockJsFileName);
|
|
|
|
await new Promise((resolve) => {
|
|
stream.on('error', (error) => {
|
|
expect(error).toStrictEqual(new Error('lint failure'));
|
|
expect(lintTransformedFileMock).toHaveBeenCalledTimes(1);
|
|
expect(lintTransformedFileMock).toHaveBeenCalledWith(
|
|
filePrefix,
|
|
mockJsFileName,
|
|
);
|
|
resolve();
|
|
});
|
|
|
|
stream.end(fileContent);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('removeFencedCode', () => {
|
|
const mockFileName = 'file.js';
|
|
|
|
// Valid inputs
|
|
['main', 'flask', 'beta'].forEach((buildType) => {
|
|
const active = buildTypesConfig.buildTypes[buildType].features;
|
|
const all = Object.keys(buildTypesConfig.features);
|
|
const features = getFeatures({ all, active });
|
|
it(`transforms file with fences for build type "${buildType}"`, () => {
|
|
expect(
|
|
removeFencedCode(
|
|
mockFileName,
|
|
features,
|
|
testData.validInputs.withFences,
|
|
),
|
|
).toStrictEqual(testData.validOutputs[buildType]);
|
|
|
|
expect(
|
|
removeFencedCode(
|
|
mockFileName,
|
|
features,
|
|
testData.validInputs.extraContentWithFences,
|
|
),
|
|
).toStrictEqual(testData.validOutputsWithExtraContent[buildType]);
|
|
|
|
// Ensure that the minimal input template is in fact valid
|
|
const minimalInput = getMinimalFencedCode(`build-${buildType}`);
|
|
expect(
|
|
removeFencedCode(mockFileName, features, minimalInput),
|
|
).toStrictEqual([minimalInput, false]);
|
|
});
|
|
|
|
it(`does not modify file without fences for build type "${buildType}"`, () => {
|
|
expect(
|
|
removeFencedCode(
|
|
mockFileName,
|
|
features,
|
|
testData.validInputs.withoutFences,
|
|
),
|
|
).toStrictEqual([testData.validInputs.withoutFences, false]);
|
|
|
|
expect(
|
|
removeFencedCode(
|
|
mockFileName,
|
|
features,
|
|
testData.validInputs.extraContentWithoutFences,
|
|
),
|
|
).toStrictEqual([
|
|
testData.validInputs.extraContentWithoutFences,
|
|
false,
|
|
]);
|
|
});
|
|
});
|
|
|
|
// This is an edge case for the splicing function
|
|
it('transforms file with two fence lines', () => {
|
|
expect(
|
|
removeFencedCode(
|
|
mockFileName,
|
|
getFeatures({
|
|
active: [FLASK_BUILD],
|
|
all: [FLASK_BUILD, MAIN_BUILD],
|
|
}),
|
|
getMinimalFencedCode(MAIN_BUILD),
|
|
),
|
|
).toStrictEqual(['', true]);
|
|
});
|
|
|
|
it('ignores sentinels preceded by non-whitespace', () => {
|
|
const validBeginDirective = '///: BEGIN:ONLY_INCLUDE_IN(build-flask)\n';
|
|
const ignoredLines = [
|
|
`a ${validBeginDirective}`,
|
|
`2 ${validBeginDirective}`,
|
|
`@ ${validBeginDirective}`,
|
|
];
|
|
|
|
ignoredLines.forEach((ignoredLine) => {
|
|
// These inputs will be transformed
|
|
expect(
|
|
removeFencedCode(
|
|
mockFileName,
|
|
getFeatures({
|
|
active: [FLASK_BUILD],
|
|
all: [FLASK_BUILD, MAIN_BUILD],
|
|
}),
|
|
getMinimalFencedCode(MAIN_BUILD).concat(ignoredLine),
|
|
),
|
|
).toStrictEqual([ignoredLine, true]);
|
|
|
|
const modifiedInputWithoutFences =
|
|
testData.validInputs.withoutFences.concat(ignoredLine);
|
|
|
|
// These inputs will not be transformed
|
|
expect(
|
|
removeFencedCode(
|
|
mockFileName,
|
|
getFeatures({ active: [FLASK_BUILD], all: [FLASK_BUILD] }),
|
|
modifiedInputWithoutFences,
|
|
),
|
|
).toStrictEqual([modifiedInputWithoutFences, false]);
|
|
});
|
|
});
|
|
|
|
// Invalid inputs
|
|
it('rejects empty fences', () => {
|
|
const jsComment = '// A comment\n';
|
|
|
|
const emptyFence = getMinimalFencedCode()
|
|
.split('\n')
|
|
.filter((line) => line.startsWith('///:'))
|
|
.map((line) => `${line}\n`)
|
|
.join('');
|
|
|
|
const emptyFenceWithPrefix = jsComment.concat(emptyFence);
|
|
const emptyFenceWithSuffix = emptyFence.concat(jsComment);
|
|
const emptyFenceSurrounded = emptyFenceWithPrefix.concat(jsComment);
|
|
|
|
const inputs = [
|
|
emptyFence,
|
|
emptyFenceWithPrefix,
|
|
emptyFenceWithSuffix,
|
|
emptyFenceSurrounded,
|
|
];
|
|
|
|
inputs.forEach((input) => {
|
|
expect(() =>
|
|
removeFencedCode(
|
|
mockFileName,
|
|
getFeatures({ active: [FLASK_BUILD], all: [FLASK_BUILD] }),
|
|
input,
|
|
),
|
|
).toThrow(
|
|
`Empty fence found in file "${mockFileName}":\n${emptyFence}`,
|
|
);
|
|
});
|
|
});
|
|
|
|
it('rejects sentinels not followed by a single space and a multi-character alphabetical string', () => {
|
|
// Matches the sentinel and terminus component of the first line
|
|
// beginning with "///: TERMINUS"
|
|
const fenceSentinelAndTerminusRegex = /^\/\/\/: \w+/mu;
|
|
|
|
const replacements = [
|
|
'///:BEGIN',
|
|
'///:XBEGIN',
|
|
'///:_BEGIN',
|
|
'///:B',
|
|
'///:_',
|
|
'///: ',
|
|
'///: B',
|
|
'///:',
|
|
];
|
|
|
|
replacements.forEach((replacement) => {
|
|
expect(() =>
|
|
removeFencedCode(
|
|
mockFileName,
|
|
getFeatures({ active: [FLASK_BUILD], all: [FLASK_BUILD] }),
|
|
getMinimalFencedCode().replace(
|
|
fenceSentinelAndTerminusRegex,
|
|
replacement,
|
|
),
|
|
),
|
|
).toThrow(
|
|
/Fence sentinel must be followed by a single space and an alphabetical string of two or more characters.$/u,
|
|
);
|
|
});
|
|
});
|
|
|
|
it('rejects malformed BEGIN directives', () => {
|
|
// This is the first line of the minimal input template
|
|
const directiveString = '///: BEGIN:ONLY_INCLUDE_IN(build-flask)';
|
|
|
|
const replacements = [
|
|
// Invalid terminus
|
|
'///: BE_GIN:BEGIN:ONLY_INCLUDE_IN(build-flask)',
|
|
'///: BE6IN:BEGIN:ONLY_INCLUDE_IN(build-flask)',
|
|
'///: BEGIN7:BEGIN:ONLY_INCLUDE_IN(build-flask)',
|
|
'///: BeGIN:ONLY_INCLUDE_IN(build-flask)',
|
|
'///: BE3:BEGIN:ONLY_INCLUDE_IN(build-flask)',
|
|
'///: BEG-IN:BEGIN:ONLY_INCLUDE_IN(build-flask)',
|
|
'///: BEG N:BEGIN:ONLY_INCLUDE_IN(build-flask)',
|
|
|
|
// Invalid commands
|
|
'///: BEGIN:ONLY-INCLUDE_IN(flask)',
|
|
'///: BEGIN:ONLY_INCLUDE:IN(flask)',
|
|
'///: BEGIN:ONL6_INCLUDE_IN(flask)',
|
|
'///: BEGIN:ONLY_IN@LUDE_IN(flask)',
|
|
'///: BEGIN:ONLy_INCLUDE_IN(build-flask)',
|
|
'///: BEGIN:ONLY INCLUDE_IN(flask)',
|
|
|
|
// Invalid parameters
|
|
'///: BEGIN:ONLY_INCLUDE_IN(,flask)',
|
|
'///: BEGIN:ONLY_INCLUDE_IN(build-flask,)',
|
|
'///: BEGIN:ONLY_INCLUDE_IN(build-flask,,main)',
|
|
'///: BEGIN:ONLY_INCLUDE_IN(,)',
|
|
'///: BEGIN:ONLY_INCLUDE_IN()',
|
|
'///: BEGIN:ONLY_INCLUDE_IN( )',
|
|
'///: BEGIN:ONLY_INCLUDE_IN(build-flask]',
|
|
'///: BEGIN:ONLY_INCLUDE_IN[flask)',
|
|
'///: BEGIN:ONLY_INCLUDE_IN(build-flask.main)',
|
|
'///: BEGIN:ONLY_INCLUDE_IN(build-flask,@)',
|
|
'///: BEGIN:ONLY_INCLUDE_IN(fla k)',
|
|
|
|
// Stuff after the directive
|
|
'///: BEGIN:ONLY_INCLUDE_IN(build-flask) A',
|
|
'///: BEGIN:ONLY_INCLUDE_IN(build-flask) 9',
|
|
'///: BEGIN:ONLY_INCLUDE_IN(build-flask)A',
|
|
'///: BEGIN:ONLY_INCLUDE_IN(build-flask)9',
|
|
'///: BEGIN:ONLY_INCLUDE_IN(build-flask)_',
|
|
'///: BEGIN:ONLY_INCLUDE_IN(build-flask))',
|
|
];
|
|
|
|
replacements.forEach((replacement) => {
|
|
expect(() =>
|
|
removeFencedCode(
|
|
mockFileName,
|
|
getFeatures({ active: [FLASK_BUILD], all: [FLASK_BUILD] }),
|
|
getMinimalFencedCode().replace(directiveString, replacement),
|
|
),
|
|
).toThrow(
|
|
new RegExp(
|
|
`${replacement.replace(
|
|
/([()[\]])/gu,
|
|
'\\$1',
|
|
)}":\nFailed to parse fence directive.$`,
|
|
'u',
|
|
),
|
|
);
|
|
});
|
|
});
|
|
|
|
it('rejects malformed END directives', () => {
|
|
// This is the last line of the minimal input template
|
|
const directiveString = '///: END:ONLY_INCLUDE_IN';
|
|
|
|
const replacements = [
|
|
// Invalid terminus
|
|
'///: ENx:ONLY_INCLUDE_IN',
|
|
'///: EN3:ONLY_INCLUDE_IN',
|
|
'///: EN_:ONLY_INCLUDE_IN',
|
|
'///: EN :ONLY_INCLUDE_IN',
|
|
'///: EN::ONLY_INCLUDE_IN',
|
|
|
|
// Invalid commands
|
|
'///: END:ONLY-INCLUDE_IN',
|
|
'///: END::ONLY_INCLUDE_IN',
|
|
'///: END:ONLY_INCLUDE:IN',
|
|
'///: END:ONL6_INCLUDE_IN',
|
|
'///: END:ONLY_IN@LUDE_IN',
|
|
'///: END:ONLy_INCLUDE_IN',
|
|
'///: END:ONLY INCLUDE_IN',
|
|
|
|
// Stuff after the directive
|
|
'///: END:ONLY_INCLUDE_IN A',
|
|
'///: END:ONLY_INCLUDE_IN 9',
|
|
'///: END:ONLY_INCLUDE_IN _',
|
|
];
|
|
|
|
replacements.forEach((replacement) => {
|
|
expect(() =>
|
|
removeFencedCode(
|
|
mockFileName,
|
|
getFeatures({ active: [FLASK_BUILD], all: [FLASK_BUILD] }),
|
|
getMinimalFencedCode().replace(directiveString, replacement),
|
|
),
|
|
).toThrow(
|
|
new RegExp(
|
|
`${replacement}":\nFailed to parse fence directive.$`,
|
|
'u',
|
|
),
|
|
);
|
|
});
|
|
});
|
|
|
|
it('rejects files with uneven number of fence lines', () => {
|
|
const additions = [
|
|
'///: BEGIN:ONLY_INCLUDE_IN(build-flask)',
|
|
'///: END:ONLY_INCLUDE_IN',
|
|
];
|
|
additions.forEach((addition) => {
|
|
expect(() =>
|
|
removeFencedCode(
|
|
mockFileName,
|
|
getFeatures({ active: [FLASK_BUILD], all: [FLASK_BUILD] }),
|
|
getMinimalFencedCode().concat(addition),
|
|
),
|
|
).toThrow(
|
|
/A valid fence consists of two fence lines, but the file contains an uneven number, "3", of fence lines.$/u,
|
|
);
|
|
});
|
|
});
|
|
|
|
it('rejects invalid terminuses', () => {
|
|
const testCases = [
|
|
['BEGIN', ['KAPLAR', 'FLASK', 'FOO']],
|
|
['END', ['KAPLAR', 'FOO', 'BAR']],
|
|
];
|
|
|
|
testCases.forEach(([validTerminus, replacements]) => {
|
|
replacements.forEach((replacement) => {
|
|
expect(() =>
|
|
removeFencedCode(
|
|
mockFileName,
|
|
getFeatures({ active: [FLASK_BUILD], all: [FLASK_BUILD] }),
|
|
getMinimalFencedCode().replace(validTerminus, replacement),
|
|
),
|
|
).toThrow(
|
|
new RegExp(
|
|
`Line contains invalid directive terminus "${replacement}".$`,
|
|
'u',
|
|
),
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('rejects invalid commands', () => {
|
|
const testCases = [
|
|
[/ONLY_INCLUDE_IN\(/mu, ['ONLY_KEEP_IN(', 'FLASK(', 'FOO(']],
|
|
[/ONLY_INCLUDE_IN$/mu, ['ONLY_KEEP_IN', 'FLASK', 'FOO']],
|
|
];
|
|
|
|
testCases.forEach(([validCommand, replacements]) => {
|
|
replacements.forEach((replacement) => {
|
|
expect(() =>
|
|
removeFencedCode(
|
|
mockFileName,
|
|
getFeatures({ active: [FLASK_BUILD], all: [FLASK_BUILD] }),
|
|
getMinimalFencedCode().replace(validCommand, replacement),
|
|
),
|
|
).toThrow(
|
|
new RegExp(
|
|
`Line contains invalid directive command "${replacement.replace(
|
|
'(',
|
|
'',
|
|
)}".$`,
|
|
'u',
|
|
),
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
it('rejects invalid command parameters', () => {
|
|
const testCases = [
|
|
[
|
|
'bar',
|
|
['bar', 'build-flask,bar', 'build-flask,build-beta,build-main,bar'],
|
|
],
|
|
[
|
|
'Foo',
|
|
['Foo', 'build-flask,Foo', 'build-flask,build-beta,build-main,Foo'],
|
|
],
|
|
[
|
|
'b3ta',
|
|
[
|
|
'b3ta',
|
|
'build-flask,b3ta',
|
|
'build-flask,build-beta,build-main,b3ta',
|
|
],
|
|
],
|
|
[
|
|
'bEta',
|
|
[
|
|
'bEta',
|
|
'build-flask,bEta',
|
|
'build-flask,build-beta,build-main,bEta',
|
|
],
|
|
],
|
|
];
|
|
|
|
testCases.forEach(([invalidParam, replacements]) => {
|
|
replacements.forEach((replacement) => {
|
|
expect(() =>
|
|
removeFencedCode(
|
|
mockFileName,
|
|
getFeatures({
|
|
active: [FLASK_BUILD],
|
|
all: [FLASK_BUILD, MAIN_BUILD, 'build-beta'],
|
|
}),
|
|
getMinimalFencedCode(replacement),
|
|
),
|
|
).toThrow(
|
|
new RegExp(
|
|
`"${invalidParam}" is not a declared build feature.$`,
|
|
'u',
|
|
),
|
|
);
|
|
});
|
|
});
|
|
|
|
// Should fail for empty params
|
|
expect(() =>
|
|
removeFencedCode(
|
|
mockFileName,
|
|
getFeatures({ active: [FLASK_BUILD], all: [FLASK_BUILD] }),
|
|
getMinimalFencedCode('').replace('()', ''),
|
|
),
|
|
).toThrow(/No params specified.$/u);
|
|
});
|
|
|
|
it('rejects directive pairs with wrong terminus order', () => {
|
|
// We need more than one directive pair for this test
|
|
const input = getMinimalFencedCode().concat(
|
|
getMinimalFencedCode('build-beta'),
|
|
);
|
|
|
|
const expectedBeginError =
|
|
'The first directive of a pair must be a "BEGIN" directive.';
|
|
const expectedEndError =
|
|
'The second directive of a pair must be an "END" directive.';
|
|
const testCases = [
|
|
[
|
|
'BEGIN:ONLY_INCLUDE_IN(build-flask)',
|
|
'END:ONLY_INCLUDE_IN',
|
|
expectedBeginError,
|
|
],
|
|
[
|
|
/END:ONLY_INCLUDE_IN/mu,
|
|
'BEGIN:ONLY_INCLUDE_IN(build-main)',
|
|
expectedEndError,
|
|
],
|
|
[
|
|
'BEGIN:ONLY_INCLUDE_IN(build-beta)',
|
|
'END:ONLY_INCLUDE_IN',
|
|
expectedBeginError,
|
|
],
|
|
];
|
|
|
|
testCases.forEach(([target, replacement, expectedError]) => {
|
|
expect(() =>
|
|
removeFencedCode(
|
|
mockFileName,
|
|
getFeatures({ active: [FLASK_BUILD], all: [FLASK_BUILD] }),
|
|
input.replace(target, replacement),
|
|
),
|
|
).toThrow(expectedError);
|
|
});
|
|
});
|
|
|
|
it('ignores files with inline source maps', () => {
|
|
// This is so that there isn't an unnecessary second execution of
|
|
// removeFencedCode with a transpiled version of the same file
|
|
const input = getTestData().validInputs.extraContentWithFences.concat(
|
|
'\n//# sourceMappingURL=as32e32wcwc2234f2ew32cnin4243f4nv9nsdoivnxzoivnd',
|
|
);
|
|
expect(
|
|
removeFencedCode(
|
|
mockFileName,
|
|
getFeatures({ active: [FLASK_BUILD], all: [FLASK_BUILD] }),
|
|
input,
|
|
),
|
|
).toStrictEqual([input, false]);
|
|
});
|
|
|
|
// We can't do this until there's more than one command
|
|
it.todo('rejects directive pairs with mismatched commands');
|
|
});
|
|
});
|
|
|
|
function getTestData() {
|
|
const data = {
|
|
validInputs: {
|
|
withFences: `
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop)
|
|
Conditionally_Included
|
|
///: END:ONLY_INCLUDE_IN
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop)
|
|
Conditionally_Included
|
|
|
|
Conditionally_Included
|
|
Conditionally_Included
|
|
///: END:ONLY_INCLUDE_IN
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-flask)
|
|
|
|
Conditionally_Included
|
|
Conditionally_Included
|
|
///: END:ONLY_INCLUDE_IN
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
///: BEGIN:ONLY_INCLUDE_IN(desktop)
|
|
|
|
Conditionally_Included
|
|
Conditionally_Included
|
|
///: END:ONLY_INCLUDE_IN
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-flask)
|
|
Conditionally_Included
|
|
Conditionally_Included
|
|
|
|
///: END:ONLY_INCLUDE_IN
|
|
///: BEGIN:ONLY_INCLUDE_IN(desktop)
|
|
Conditionally_Included
|
|
Conditionally_Included
|
|
///: END:ONLY_INCLUDE_IN
|
|
`,
|
|
|
|
extraContentWithFences: `
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop)
|
|
Conditionally_Included
|
|
///: END:ONLY_INCLUDE_IN
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop)
|
|
Conditionally_Included
|
|
|
|
Conditionally_Included
|
|
Conditionally_Included
|
|
///: END:ONLY_INCLUDE_IN
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-flask)
|
|
|
|
Conditionally_Included
|
|
Conditionally_Included
|
|
///: END:ONLY_INCLUDE_IN
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
///: BEGIN:ONLY_INCLUDE_IN(desktop)
|
|
Conditionally_Included
|
|
Conditionally_Included
|
|
///: END:ONLY_INCLUDE_IN
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-flask)
|
|
Conditionally_Included
|
|
Conditionally_Included
|
|
|
|
///: END:ONLY_INCLUDE_IN
|
|
///: BEGIN:ONLY_INCLUDE_IN(desktop)
|
|
Conditionally_Included
|
|
Conditionally_Included
|
|
|
|
///: END:ONLY_INCLUDE_IN
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
`,
|
|
|
|
withoutFences: `
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
`,
|
|
|
|
extraContentWithoutFences: `
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
`,
|
|
},
|
|
|
|
validOutputs: {
|
|
beta: [
|
|
`
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop)
|
|
Conditionally_Included
|
|
///: END:ONLY_INCLUDE_IN
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop)
|
|
Conditionally_Included
|
|
|
|
Conditionally_Included
|
|
Conditionally_Included
|
|
///: END:ONLY_INCLUDE_IN
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
`,
|
|
true,
|
|
],
|
|
flask: [
|
|
`
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop)
|
|
Conditionally_Included
|
|
///: END:ONLY_INCLUDE_IN
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop)
|
|
Conditionally_Included
|
|
|
|
Conditionally_Included
|
|
Conditionally_Included
|
|
///: END:ONLY_INCLUDE_IN
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-flask)
|
|
|
|
Conditionally_Included
|
|
Conditionally_Included
|
|
///: END:ONLY_INCLUDE_IN
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
///: BEGIN:ONLY_INCLUDE_IN(desktop)
|
|
|
|
Conditionally_Included
|
|
Conditionally_Included
|
|
///: END:ONLY_INCLUDE_IN
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-flask)
|
|
Conditionally_Included
|
|
Conditionally_Included
|
|
|
|
///: END:ONLY_INCLUDE_IN
|
|
///: BEGIN:ONLY_INCLUDE_IN(desktop)
|
|
Conditionally_Included
|
|
Conditionally_Included
|
|
///: END:ONLY_INCLUDE_IN
|
|
`,
|
|
false,
|
|
],
|
|
mmi: [
|
|
`
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
`,
|
|
true,
|
|
],
|
|
},
|
|
|
|
validOutputsWithExtraContent: {
|
|
beta: [
|
|
`
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop)
|
|
Conditionally_Included
|
|
///: END:ONLY_INCLUDE_IN
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop)
|
|
Conditionally_Included
|
|
|
|
Conditionally_Included
|
|
Conditionally_Included
|
|
///: END:ONLY_INCLUDE_IN
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
`,
|
|
true,
|
|
],
|
|
flask: [
|
|
`
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop)
|
|
Conditionally_Included
|
|
///: END:ONLY_INCLUDE_IN
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop)
|
|
Conditionally_Included
|
|
|
|
Conditionally_Included
|
|
Conditionally_Included
|
|
///: END:ONLY_INCLUDE_IN
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-flask)
|
|
|
|
Conditionally_Included
|
|
Conditionally_Included
|
|
///: END:ONLY_INCLUDE_IN
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
///: BEGIN:ONLY_INCLUDE_IN(desktop)
|
|
Conditionally_Included
|
|
Conditionally_Included
|
|
///: END:ONLY_INCLUDE_IN
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-flask)
|
|
Conditionally_Included
|
|
Conditionally_Included
|
|
|
|
///: END:ONLY_INCLUDE_IN
|
|
///: BEGIN:ONLY_INCLUDE_IN(desktop)
|
|
Conditionally_Included
|
|
Conditionally_Included
|
|
|
|
///: END:ONLY_INCLUDE_IN
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
`,
|
|
false,
|
|
],
|
|
mmi: [
|
|
`
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
Always_Included
|
|
`,
|
|
true,
|
|
],
|
|
},
|
|
};
|
|
|
|
data.validOutputs.desktop = [data.validInputs.withFences, false];
|
|
data.validOutputs.main = [data.validInputs.withoutFences, true];
|
|
|
|
data.validOutputsWithExtraContent.desktop = [
|
|
data.validInputs.extraContentWithFences,
|
|
false,
|
|
];
|
|
data.validOutputsWithExtraContent.main = [
|
|
data.validInputs.extraContentWithoutFences,
|
|
true,
|
|
];
|
|
return deepFreeze(data);
|
|
}
|