| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496 | /* Copyright 2016 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//* eslint-env node */"use strict";const autoprefixer = require("autoprefixer");const postcssDirPseudoClass = require("postcss-dir-pseudo-class");const postcssLogical = require("postcss-logical");const fs = require("fs");const gulp = require("gulp");const postcss = require("gulp-postcss");const rename = require("gulp-rename");const replace = require("gulp-replace");const mkdirp = require("mkdirp");const path = require("path");const rimraf = require("rimraf");const stream = require("stream");const exec = require("child_process").exec;const spawn = require("child_process").spawn;const spawnSync = require("child_process").spawnSync;const streamqueue = require("streamqueue");const merge = require("merge-stream");const zip = require("gulp-zip");const webpack2 = require("webpack");const webpackStream = require("webpack-stream");const Vinyl = require("vinyl");const vfs = require("vinyl-fs");const through = require("through2");const BUILD_DIR = "build/";const L10N_DIR = "l10n/";const TEST_DIR = "test/";const EXTENSION_SRC_DIR = "extensions/";const BASELINE_DIR = BUILD_DIR + "baseline/";const MOZCENTRAL_BASELINE_DIR = BUILD_DIR + "mozcentral.baseline/";const GENERIC_DIR = BUILD_DIR + "generic/";const GENERIC_LEGACY_DIR = BUILD_DIR + "generic-legacy/";const COMPONENTS_DIR = BUILD_DIR + "components/";const COMPONENTS_LEGACY_DIR = BUILD_DIR + "components-legacy/";const IMAGE_DECODERS_DIR = BUILD_DIR + "image_decoders/";const IMAGE_DECODERS_LEGACY_DIR = BUILD_DIR + "image_decoders-legacy/";const DEFAULT_PREFERENCES_DIR = BUILD_DIR + "default_preferences/";const MINIFIED_DIR = BUILD_DIR + "minified/";const MINIFIED_LEGACY_DIR = BUILD_DIR + "minified-legacy/";const JSDOC_BUILD_DIR = BUILD_DIR + "jsdoc/";const GH_PAGES_DIR = BUILD_DIR + "gh-pages/";const SRC_DIR = "src/";const LIB_DIR = BUILD_DIR + "lib/";const DIST_DIR = BUILD_DIR + "dist/";const TYPES_DIR = BUILD_DIR + "types/";const TMP_DIR = BUILD_DIR + "tmp/";const TYPESTEST_DIR = BUILD_DIR + "typestest/";const COMMON_WEB_FILES = [  "web/images/*.{png,svg,gif}",  "web/debugger.{css,js}",];const MOZCENTRAL_DIFF_FILE = "mozcentral.diff";const REPO = "git@github.com:mozilla/pdf.js.git";const DIST_REPO_URL = "https://github.com/mozilla/pdfjs-dist";const builder = require("./external/builder/builder.js");const CONFIG_FILE = "pdfjs.config";const config = JSON.parse(fs.readFileSync(CONFIG_FILE).toString());const ENV_TARGETS = [  "last 2 versions",  "Chrome >= 85",  "Firefox ESR",  "Safari >= 14",  "Node >= 14",  "> 1%",  "not IE > 0",  "not dead",];// Default Autoprefixer config used for generic, components, minified-preconst AUTOPREFIXER_CONFIG = {  overrideBrowserslist: ENV_TARGETS,};// Default Babel targets used for generic, components, minified-preconst BABEL_TARGETS = ENV_TARGETS.join(", ");const DEFINES = Object.freeze({  PRODUCTION: true,  SKIP_BABEL: true,  TESTING: undefined,  // The main build targets:  GENERIC: false,  MOZCENTRAL: false,  GECKOVIEW: false,  CHROME: false,  MINIFIED: false,  COMPONENTS: false,  LIB: false,  IMAGE_DECODERS: false,});function transform(charEncoding, transformFunction) {  return through.obj(function (vinylFile, enc, done) {    const transformedFile = vinylFile.clone();    transformedFile.contents = Buffer.from(      transformFunction(transformedFile.contents),      charEncoding    );    done(null, transformedFile);  });}function safeSpawnSync(command, parameters, options) {  // Execute all commands in a shell.  options = options || {};  options.shell = true;  // `options.shell = true` requires parameters to be quoted.  parameters = parameters.map(param => {    if (!/[\s`~!#$*(){[|\\;'"<>?]/.test(param)) {      return param;    }    return '"' + param.replace(/([$\\"`])/g, "\\$1") + '"';  });  const result = spawnSync(command, parameters, options);  if (result.status !== 0) {    console.log(      'Error: command "' +        command +        '" with parameters "' +        parameters +        '" exited with code ' +        result.status    );    process.exit(result.status);  }  return result;}function startNode(args, options) {  // Node.js decreased the maximum header size from 80 KB to 8 KB in newer  // releases, which is not sufficient for some of our reference test files  // (such as `issue6360.pdf`), so we need to restore this value. Note that  // this argument needs to be before all other arguments as it needs to be  // passed to the Node.js process itself and not to the script that it runs.  args.unshift("--max-http-header-size=80000");  return spawn("node", args, options);}function createStringSource(filename, content) {  const source = stream.Readable({ objectMode: true });  source._read = function () {    this.push(      new Vinyl({        path: filename,        contents: Buffer.from(content),      })    );    this.push(null);  };  return source;}function createWebpackConfig(  defines,  output,  {    disableVersionInfo = false,    disableSourceMaps = false,    disableLicenseHeader = false,    defaultPreferencesDir = null,  } = {}) {  const versionInfo = !disableVersionInfo    ? getVersionJSON()    : { version: 0, commit: 0 };  const bundleDefines = builder.merge(defines, {    BUNDLE_VERSION: versionInfo.version,    BUNDLE_BUILD: versionInfo.commit,    TESTING:      defines.TESTING !== undefined        ? defines.TESTING        : process.env.TESTING === "true",    DEFAULT_PREFERENCES: defaultPreferencesDir      ? getDefaultPreferences(defaultPreferencesDir)      : {},    DIALOG_POLYFILL_CSS:      defines.GENERIC && !defines.SKIP_BABEL ? getDialogPolyfillCSS() : "",  });  const licenseHeaderLibre = fs    .readFileSync("./src/license_header_libre.js")    .toString();  const enableSourceMaps =    !bundleDefines.MOZCENTRAL &&    !bundleDefines.CHROME &&    !bundleDefines.LIB &&    !bundleDefines.TESTING &&    !disableSourceMaps;  const skipBabel = bundleDefines.SKIP_BABEL;  // `core-js` (see https://github.com/zloirock/core-js/issues/514), and  // `src/core/{glyphlist,unicode}.js` (Babel is too slow for those when  // source-maps are enabled) should be excluded from processing.  const babelExcludes = ["node_modules[\\\\\\/]core-js"];  if (enableSourceMaps) {    babelExcludes.push("src[\\\\\\/]core[\\\\\\/](glyphlist|unicode)");  }  const babelExcludeRegExp = new RegExp(`(${babelExcludes.join("|")})`);  const babelPlugins = ["@babel/plugin-transform-modules-commonjs"];  const plugins = [];  if (!disableLicenseHeader) {    plugins.push(      new webpack2.BannerPlugin({ banner: licenseHeaderLibre, raw: true })    );  }  const experiments =    output.library?.type === "module" ? { outputModule: true } : undefined;  // Required to expose e.g., the `window` object.  output.globalObject = "globalThis";  return {    mode: "none",    experiments,    output,    performance: {      hints: false, // Disable messages about larger file sizes.    },    plugins,    resolve: {      alias: {        pdfjs: path.join(__dirname, "src"),        "pdfjs-web": path.join(__dirname, "web"),        "pdfjs-lib": path.join(__dirname, "web/pdfjs"),        "pdfjs-fitCurve": path.join(__dirname, "src/display/editor/fit_curve"),      },    },    devtool: enableSourceMaps ? "source-map" : undefined,    module: {      rules: [        {          loader: "babel-loader",          exclude: babelExcludeRegExp,          options: {            presets: skipBabel ? undefined : ["@babel/preset-env"],            plugins: babelPlugins,            targets: BABEL_TARGETS,          },        },        {          loader: path.join(__dirname, "external/webpack/pdfjsdev-loader.js"),          options: {            rootPath: __dirname,            saveComments: false,            defines: bundleDefines,          },        },      ],    },    // Avoid shadowing actual Node.js variables with polyfills, by disabling    // polyfills/mocks - https://webpack.js.org/configuration/node/    node: false,  };}function webpack2Stream(webpackConfig) {  // Replacing webpack1 to webpack2 in the webpack-stream.  return webpackStream(webpackConfig, webpack2);}function getVersionJSON() {  return JSON.parse(fs.readFileSync(BUILD_DIR + "version.json").toString());}function checkChromePreferencesFile(chromePrefsPath, webPrefs) {  const chromePrefs = JSON.parse(fs.readFileSync(chromePrefsPath).toString());  const chromePrefsKeys = Object.keys(chromePrefs.properties).filter(key => {    const description = chromePrefs.properties[key].description;    // Deprecated keys are allowed in the managed preferences file.    // The code maintained is responsible for adding migration logic to    // extensions/chromium/options/migration.js and web/chromecom.js .    return !description || !description.startsWith("DEPRECATED.");  });  chromePrefsKeys.sort();  const webPrefsKeys = Object.keys(webPrefs);  webPrefsKeys.sort();  if (webPrefsKeys.length !== chromePrefsKeys.length) {    console.log("Warning: Pref objects doesn't have the same length.");    return false;  }  let ret = true;  for (let i = 0, ii = webPrefsKeys.length; i < ii; i++) {    const value = webPrefsKeys[i];    if (chromePrefsKeys[i] !== value) {      ret = false;      console.log(        `Warning: not the same keys: ${chromePrefsKeys[i]} !== ${value}`      );    } else if (chromePrefs.properties[value].default !== webPrefs[value]) {      ret = false;      console.log(        `Warning: not the same values (for "${value}"): ` +          `${chromePrefs.properties[value].default} !== ${webPrefs[value]}`      );    }  }  return ret;}function replaceWebpackRequire() {  // Produced bundles can be rebundled again, avoid collisions (e.g. in api.js)  // by renaming  __webpack_require__ to something else.  return replace("__webpack_require__", "__w_pdfjs_require__");}function replaceNonWebpackImport() {  return replace("__non_webpack_import__", "import");}function replaceJSRootName(amdName, jsName) {  // Saving old-style JS module name.  return replace(    'root["' + amdName + '"] = factory()',    'root["' + amdName + '"] = root.' + jsName + " = factory()"  );}function createMainBundle(defines) {  const mainAMDName = "pdfjs-dist/build/pdf";  const mainOutputName = "pdf.js";  const mainFileConfig = createWebpackConfig(defines, {    filename: mainOutputName,    library: mainAMDName,    libraryTarget: "umd",    umdNamedDefine: true,  });  return gulp    .src("./src/pdf.js")    .pipe(webpack2Stream(mainFileConfig))    .pipe(replaceWebpackRequire())    .pipe(replaceNonWebpackImport())    .pipe(replaceJSRootName(mainAMDName, "pdfjsLib"));}function createScriptingBundle(defines, extraOptions = undefined) {  const scriptingAMDName = "pdfjs-dist/build/pdf.scripting";  const scriptingOutputName = "pdf.scripting.js";  const scriptingFileConfig = createWebpackConfig(    defines,    {      filename: scriptingOutputName,      library: scriptingAMDName,      libraryTarget: "umd",      umdNamedDefine: true,    },    extraOptions  );  return gulp    .src("./src/pdf.scripting.js")    .pipe(webpack2Stream(scriptingFileConfig))    .pipe(replaceWebpackRequire())    .pipe(replaceNonWebpackImport())    .pipe(      replace(        'root["' + scriptingAMDName + '"] = factory()',        "root.pdfjsScripting = factory()"      )    );}function createSandboxExternal(defines) {  const preprocessor2 = require("./external/builder/preprocessor2.js");  const licenseHeader = fs.readFileSync("./src/license_header.js").toString();  const ctx = {    saveComments: false,    defines,  };  return gulp.src("./src/pdf.sandbox.external.js").pipe(    transform("utf8", content => {      content = preprocessor2.preprocessPDFJSCode(ctx, content);      return `${licenseHeader}\n${content}`;    })  );}function createTemporaryScriptingBundle(defines, extraOptions = undefined) {  return createScriptingBundle(defines, {    disableVersionInfo: !!(extraOptions && extraOptions.disableVersionInfo),    disableSourceMaps: true,    disableLicenseHeader: true,  }).pipe(gulp.dest(TMP_DIR));}function createSandboxBundle(defines, extraOptions = undefined) {  const sandboxAMDName = "pdfjs-dist/build/pdf.sandbox";  const sandboxOutputName = "pdf.sandbox.js";  const scriptingPath = TMP_DIR + "pdf.scripting.js";  // Insert the source as a string to be `eval`-ed in the sandbox.  const sandboxDefines = builder.merge(defines, {    PDF_SCRIPTING_JS_SOURCE: fs.readFileSync(scriptingPath).toString(),  });  fs.unlinkSync(scriptingPath);  const sandboxFileConfig = createWebpackConfig(    sandboxDefines,    {      filename: sandboxOutputName,      library: sandboxAMDName,      libraryTarget: "umd",      umdNamedDefine: true,    },    extraOptions  );  return gulp    .src("./src/pdf.sandbox.js")    .pipe(webpack2Stream(sandboxFileConfig))    .pipe(replaceWebpackRequire())    .pipe(replaceNonWebpackImport())    .pipe(replaceJSRootName(sandboxAMDName, "pdfjsSandbox"));}function createWorkerBundle(defines) {  const workerAMDName = "pdfjs-dist/build/pdf.worker";  const workerOutputName = "pdf.worker.js";  const workerFileConfig = createWebpackConfig(defines, {    filename: workerOutputName,    library: workerAMDName,    libraryTarget: "umd",    umdNamedDefine: true,  });  return gulp    .src("./src/pdf.worker.js")    .pipe(webpack2Stream(workerFileConfig))    .pipe(replaceWebpackRequire())    .pipe(replaceNonWebpackImport())    .pipe(replaceJSRootName(workerAMDName, "pdfjsWorker"));}function createWebBundle(defines, options) {  const viewerOutputName = "viewer.js";  const viewerFileConfig = createWebpackConfig(    defines,    {      filename: viewerOutputName,    },    {      defaultPreferencesDir: options.defaultPreferencesDir,    }  );  return gulp    .src("./web/viewer.js")    .pipe(webpack2Stream(viewerFileConfig))    .pipe(replaceNonWebpackImport());}function createGVWebBundle(defines, options) {  const viewerOutputName = "viewer-geckoview.js";  defines = builder.merge(defines, { GECKOVIEW: true });  const viewerFileConfig = createWebpackConfig(    defines,    {      filename: viewerOutputName,    },    {      defaultPreferencesDir: options.defaultPreferencesDir,    }  );  return gulp    .src("./web/viewer-geckoview.js")    .pipe(webpack2Stream(viewerFileConfig))    .pipe(replaceNonWebpackImport());}function createComponentsBundle(defines) {  const componentsAMDName = "pdfjs-dist/web/pdf_viewer";  const componentsOutputName = "pdf_viewer.js";  const componentsFileConfig = createWebpackConfig(defines, {    filename: componentsOutputName,    library: componentsAMDName,    libraryTarget: "umd",    umdNamedDefine: true,  });  return gulp    .src("./web/pdf_viewer.component.js")    .pipe(webpack2Stream(componentsFileConfig))    .pipe(replaceWebpackRequire())    .pipe(replaceNonWebpackImport())    .pipe(replaceJSRootName(componentsAMDName, "pdfjsViewer"));}function createImageDecodersBundle(defines) {  const imageDecodersAMDName = "pdfjs-dist/image_decoders/pdf.image_decoders";  const imageDecodersOutputName = "pdf.image_decoders.js";  const componentsFileConfig = createWebpackConfig(defines, {    filename: imageDecodersOutputName,    library: imageDecodersAMDName,    libraryTarget: "umd",    umdNamedDefine: true,  });  return gulp    .src("./src/pdf.image_decoders.js")    .pipe(webpack2Stream(componentsFileConfig))    .pipe(replaceWebpackRequire())    .pipe(replaceNonWebpackImport())    .pipe(replaceJSRootName(imageDecodersAMDName, "pdfjsImageDecoders"));}function createFitCurveBundle(defines) {  const fitCurveOutputName = "fit_curve.js";  const fitCurveFileConfig = createWebpackConfig(    defines,    {      filename: fitCurveOutputName,      library: {        type: "module",      },    },    {      disableVersionInfo: true,    }  );  return gulp    .src("src/display/editor/fit_curve.js")    .pipe(webpack2Stream(fitCurveFileConfig));}function createCMapBundle() {  return gulp.src(["external/bcmaps/*.bcmap", "external/bcmaps/LICENSE"], {    base: "external/bcmaps",  });}function createStandardFontBundle() {  return gulp.src(    [      "external/standard_fonts/*.pfb",      "external/standard_fonts/*.ttf",      "external/standard_fonts/LICENSE_FOXIT",      "external/standard_fonts/LICENSE_LIBERATION",    ],    {      base: "external/standard_fonts",    }  );}function checkFile(filePath) {  try {    const stat = fs.lstatSync(filePath);    return stat.isFile();  } catch (e) {    return false;  }}function checkDir(dirPath) {  try {    const stat = fs.lstatSync(dirPath);    return stat.isDirectory();  } catch (e) {    return false;  }}function replaceInFile(filePath, find, replacement) {  let content = fs.readFileSync(filePath).toString();  content = content.replace(find, replacement);  fs.writeFileSync(filePath, content);}function getTempFile(prefix, suffix) {  mkdirp.sync(BUILD_DIR + "tmp/");  const bytes = require("crypto").randomBytes(6).toString("hex");  const filePath = BUILD_DIR + "tmp/" + prefix + bytes + suffix;  fs.writeFileSync(filePath, "");  return filePath;}function createTestSource(testsName, { bot = false, xfaOnly = false } = {}) {  const source = stream.Readable({ objectMode: true });  source._read = function () {    console.log();    console.log("### Running " + testsName + " tests");    const PDF_TEST = process.env.PDF_TEST || "test_manifest.json";    let forceNoChrome = false;    const args = ["test.js"];    switch (testsName) {      case "browser":        if (!bot) {          args.push("--reftest");        } else {          const os = process.env.OS;          if (/windows/i.test(os)) {            // The browser-tests are too slow in Google Chrome on the Windows            // bot, causing a timeout, hence disabling them for now.            forceNoChrome = true;          }        }        if (xfaOnly) {          args.push("--xfaOnly");        }        args.push("--manifestFile=" + PDF_TEST);        break;      case "unit":        args.push("--unitTest");        break;      case "font":        args.push("--fontTest");        break;      case "integration":        args.push("--integration");        break;      default:        this.emit("error", new Error("Unknown name: " + testsName));        return null;    }    if (bot) {      args.push("--strictVerify");    }    if (process.argv.includes("--noChrome") || forceNoChrome) {      args.push("--noChrome");    }    const testProcess = startNode(args, { cwd: TEST_DIR, stdio: "inherit" });    testProcess.on("close", function (code) {      source.push(null);    });    return undefined;  };  return source;}function makeRef(done, bot) {  console.log();  console.log("### Creating reference images");  let forceNoChrome = false;  const args = ["test.js", "--masterMode"];  if (bot) {    const os = process.env.OS;    if (/windows/i.test(os)) {      // The browser-tests are too slow in Google Chrome on the Windows      // bot, causing a timeout, hence disabling them for now.      forceNoChrome = true;    }    args.push("--noPrompts", "--strictVerify");  }  if (process.argv.includes("--noChrome") || forceNoChrome) {    args.push("--noChrome");  }  const testProcess = startNode(args, { cwd: TEST_DIR, stdio: "inherit" });  testProcess.on("close", function (code) {    done();  });}gulp.task("default", function (done) {  console.log("Available tasks:");  const tasks = Object.keys(gulp.registry().tasks());  for (const taskName of tasks.sort()) {    if (taskName.endsWith("-pre")) {      continue;    }    console.log("  " + taskName);  }  done();});function createBuildNumber(done) {  console.log();  console.log("### Getting extension build number");  exec(    "git log --format=oneline " + config.baseVersion + "..",    function (err, stdout, stderr) {      let buildNumber = 0;      if (!err) {        // Build number is the number of commits since base version        buildNumber = stdout ? stdout.match(/\n/g).length : 0;      } else {        console.log(          "This is not a Git repository; using default build number."        );      }      console.log("Extension build number: " + buildNumber);      const version = config.versionPrefix + buildNumber;      exec('git log --format="%h" -n 1', function (err2, stdout2, stderr2) {        let buildCommit = "";        if (!err2) {          buildCommit = stdout2.replace("\n", "");        }        createStringSource(          "version.json",          JSON.stringify(            {              version,              build: buildNumber,              commit: buildCommit,            },            null,            2          )        )          .pipe(gulp.dest(BUILD_DIR))          .on("end", done);      });    }  );}function buildDefaultPreferences(defines, dir) {  console.log();  console.log("### Building default preferences");  const bundleDefines = builder.merge(defines, {    LIB: true,    SKIP_BABEL: false,    BUNDLE_VERSION: 0, // Dummy version    BUNDLE_BUILD: 0, // Dummy build    TESTING:      defines.TESTING !== undefined        ? defines.TESTING        : process.env.TESTING === "true",  });  const inputStream = merge([    gulp.src(["web/app_options.js"], {      base: ".",    }),  ]);  return buildLibHelper(    bundleDefines,    inputStream,    DEFAULT_PREFERENCES_DIR + dir  );}function getDefaultPreferences(dir) {  const { AppOptions, OptionKind } = require("./" +    DEFAULT_PREFERENCES_DIR +    dir +    "web/app_options.js");  return AppOptions.getAll(OptionKind.PREFERENCE);}function getDialogPolyfillCSS() {  return fs    .readFileSync("node_modules/dialog-polyfill/dist/dialog-polyfill.css")    .toString();}gulp.task("locale", function () {  const VIEWER_LOCALE_OUTPUT = "web/locale/";  console.log();  console.log("### Building localization files");  rimraf.sync(VIEWER_LOCALE_OUTPUT);  mkdirp.sync(VIEWER_LOCALE_OUTPUT);  const subfolders = fs.readdirSync(L10N_DIR);  subfolders.sort();  let viewerOutput = "";  const locales = [];  for (const locale of subfolders) {    const dirPath = L10N_DIR + locale;    if (!checkDir(dirPath)) {      continue;    }    if (!/^[a-z][a-z]([a-z])?(-[A-Z][A-Z])?$/.test(locale)) {      console.log("Skipping invalid locale: " + locale);      continue;    }    mkdirp.sync(VIEWER_LOCALE_OUTPUT + "/" + locale);    locales.push(locale);    if (checkFile(dirPath + "/viewer.properties")) {      viewerOutput +=        "[" +        locale +        "]\n" +        "@import url(" +        locale +        "/viewer.properties)\n\n";    }  }  return merge([    createStringSource("locale.properties", viewerOutput).pipe(      gulp.dest(VIEWER_LOCALE_OUTPUT)    ),    gulp      .src(L10N_DIR + "/{" + locales.join(",") + "}/viewer.properties", {        base: L10N_DIR,      })      .pipe(gulp.dest(VIEWER_LOCALE_OUTPUT)),  ]);});gulp.task("cmaps", function (done) {  const CMAP_INPUT = "external/cmaps";  const VIEWER_CMAP_OUTPUT = "external/bcmaps";  console.log();  console.log("### Building cmaps");  // Testing a file that usually present.  if (!checkFile(CMAP_INPUT + "/UniJIS-UCS2-H")) {    console.log("./external/cmaps has no cmap files, download them from:");    console.log("  https://github.com/adobe-type-tools/cmap-resources");    throw new Error("cmap files were not found");  }  // Remove old bcmap files.  fs.readdirSync(VIEWER_CMAP_OUTPUT).forEach(function (file) {    if (/\.bcmap$/i.test(file)) {      fs.unlinkSync(VIEWER_CMAP_OUTPUT + "/" + file);    }  });  const compressCmaps =    require("./external/cmapscompress/compress.js").compressCmaps;  compressCmaps(CMAP_INPUT, VIEWER_CMAP_OUTPUT, true);  done();});function preprocessCSS(source, defines) {  const outName = getTempFile("~preprocess", ".css");  builder.preprocess(source, outName, defines);  let out = fs.readFileSync(outName).toString();  fs.unlinkSync(outName);  // Strip out all license headers in the middle.  const reg = /\n\/\* Copyright(.|\n)*?Mozilla Foundation(.|\n)*?\*\//g;  out = out.replace(reg, "");  const i = source.lastIndexOf("/");  return createStringSource(source.substr(i + 1), out);}function preprocessHTML(source, defines) {  const outName = getTempFile("~preprocess", ".html");  builder.preprocess(source, outName, defines);  const out = fs.readFileSync(outName).toString();  fs.unlinkSync(outName);  const i = source.lastIndexOf("/");  return createStringSource(source.substr(i + 1), `${out.trimEnd()}\n`);}function buildGeneric(defines, dir) {  rimraf.sync(dir);  return merge([    createMainBundle(defines).pipe(gulp.dest(dir + "build")),    createWorkerBundle(defines).pipe(gulp.dest(dir + "build")),    createSandboxBundle(defines).pipe(gulp.dest(dir + "build")),    createWebBundle(defines, {      defaultPreferencesDir: defines.SKIP_BABEL        ? "generic/"        : "generic-legacy/",    }).pipe(gulp.dest(dir + "web")),    gulp.src(COMMON_WEB_FILES, { base: "web/" }).pipe(gulp.dest(dir + "web")),    gulp.src("LICENSE").pipe(gulp.dest(dir)),    gulp      .src(["web/locale/*/viewer.properties", "web/locale/locale.properties"], {        base: "web/",      })      .pipe(gulp.dest(dir + "web")),    createCMapBundle().pipe(gulp.dest(dir + "web/cmaps")),    createStandardFontBundle().pipe(gulp.dest(dir + "web/standard_fonts")),    preprocessHTML("web/viewer.html", defines).pipe(gulp.dest(dir + "web")),    preprocessCSS("web/viewer.css", defines)      .pipe(        postcss([          postcssLogical({ preserve: true }),          postcssDirPseudoClass(),          autoprefixer(AUTOPREFIXER_CONFIG),        ])      )      .pipe(gulp.dest(dir + "web")),    gulp      .src("web/compressed.tracemonkey-pldi-09.pdf")      .pipe(gulp.dest(dir + "web")),  ]);}// Builds the generic production viewer that is only compatible with up-to-date// HTML5 browsers, which implement modern ECMAScript features.gulp.task(  "generic",  gulp.series(    createBuildNumber,    "locale",    function scriptingGeneric() {      const defines = builder.merge(DEFINES, { GENERIC: true });      return merge([        buildDefaultPreferences(defines, "generic/"),        createTemporaryScriptingBundle(defines),      ]);    },    function createGeneric() {      console.log();      console.log("### Creating generic viewer");      const defines = builder.merge(DEFINES, { GENERIC: true });      return buildGeneric(defines, GENERIC_DIR);    }  ));// Builds the generic production viewer that should be compatible with most// older HTML5 browsers.gulp.task(  "generic-legacy",  gulp.series(    createBuildNumber,    "locale",    function scriptingGenericLegacy() {      const defines = builder.merge(DEFINES, {        GENERIC: true,        SKIP_BABEL: false,      });      return merge([        buildDefaultPreferences(defines, "generic-legacy/"),        createTemporaryScriptingBundle(defines),      ]);    },    function createGenericLegacy() {      console.log();      console.log("### Creating generic (legacy) viewer");      const defines = builder.merge(DEFINES, {        GENERIC: true,        SKIP_BABEL: false,      });      return buildGeneric(defines, GENERIC_LEGACY_DIR);    }  ));function buildComponents(defines, dir) {  rimraf.sync(dir);  const COMPONENTS_IMAGES = [    "web/images/annotation-*.svg",    "web/images/loading-icon.gif",    "web/images/shadow.png",  ];  return merge([    createComponentsBundle(defines).pipe(gulp.dest(dir)),    gulp.src(COMPONENTS_IMAGES).pipe(gulp.dest(dir + "images")),    preprocessCSS("web/pdf_viewer.css", defines)      .pipe(        postcss([          postcssLogical({ preserve: true }),          postcssDirPseudoClass(),          autoprefixer(AUTOPREFIXER_CONFIG),        ])      )      .pipe(gulp.dest(dir)),  ]);}gulp.task(  "components",  gulp.series(createBuildNumber, function createComponents() {    console.log();    console.log("### Creating generic components");    const defines = builder.merge(DEFINES, { COMPONENTS: true, GENERIC: true });    return buildComponents(defines, COMPONENTS_DIR);  }));gulp.task(  "components-legacy",  gulp.series(createBuildNumber, function createComponentsLegacy() {    console.log();    console.log("### Creating generic (legacy) components");    const defines = builder.merge(DEFINES, {      COMPONENTS: true,      GENERIC: true,      SKIP_BABEL: false,    });    return buildComponents(defines, COMPONENTS_LEGACY_DIR);  }));gulp.task(  "image_decoders",  gulp.series(createBuildNumber, function createImageDecoders() {    console.log();    console.log("### Creating image decoders");    const defines = builder.merge(DEFINES, {      GENERIC: true,      IMAGE_DECODERS: true,    });    return createImageDecodersBundle(defines).pipe(      gulp.dest(IMAGE_DECODERS_DIR)    );  }));gulp.task(  "image_decoders-legacy",  gulp.series(createBuildNumber, function createImageDecodersLegacy() {    console.log();    console.log("### Creating (legacy) image decoders");    const defines = builder.merge(DEFINES, {      GENERIC: true,      IMAGE_DECODERS: true,      SKIP_BABEL: false,    });    return createImageDecodersBundle(defines).pipe(      gulp.dest(IMAGE_DECODERS_LEGACY_DIR)    );  }));function buildMinified(defines, dir) {  rimraf.sync(dir);  return merge([    createMainBundle(defines).pipe(gulp.dest(dir + "build")),    createWorkerBundle(defines).pipe(gulp.dest(dir + "build")),    createSandboxBundle(defines).pipe(gulp.dest(dir + "build")),    createWebBundle(defines, {      defaultPreferencesDir: defines.SKIP_BABEL        ? "minified/"        : "minified-legacy/",    }).pipe(gulp.dest(dir + "web")),    createImageDecodersBundle(      builder.merge(defines, { IMAGE_DECODERS: true })    ).pipe(gulp.dest(dir + "image_decoders")),    gulp.src(COMMON_WEB_FILES, { base: "web/" }).pipe(gulp.dest(dir + "web")),    gulp      .src(["web/locale/*/viewer.properties", "web/locale/locale.properties"], {        base: "web/",      })      .pipe(gulp.dest(dir + "web")),    createCMapBundle().pipe(gulp.dest(dir + "web/cmaps")),    createStandardFontBundle().pipe(gulp.dest(dir + "web/standard_fonts")),    preprocessHTML("web/viewer.html", defines).pipe(gulp.dest(dir + "web")),    preprocessCSS("web/viewer.css", defines)      .pipe(        postcss([          postcssLogical({ preserve: true }),          postcssDirPseudoClass(),          autoprefixer(AUTOPREFIXER_CONFIG),        ])      )      .pipe(gulp.dest(dir + "web")),    gulp      .src("web/compressed.tracemonkey-pldi-09.pdf")      .pipe(gulp.dest(dir + "web")),  ]);}async function parseMinified(dir) {  const pdfFile = fs.readFileSync(dir + "/build/pdf.js").toString();  const pdfWorkerFile = fs    .readFileSync(dir + "/build/pdf.worker.js")    .toString();  const pdfSandboxFile = fs    .readFileSync(dir + "/build/pdf.sandbox.js")    .toString();  const pdfImageDecodersFile = fs    .readFileSync(dir + "/image_decoders/pdf.image_decoders.js")    .toString();  const viewerFiles = {    "pdf.js": pdfFile,    "viewer.js": fs.readFileSync(dir + "/web/viewer.js").toString(),  };  console.log();  console.log("### Minifying js files");  const Terser = require("terser");  const options = {    compress: {      // V8 chokes on very long sequences, work around that.      sequences: false,    },    keep_classnames: true,    keep_fnames: true,  };  fs.writeFileSync(    dir + "/web/pdf.viewer.js",    (await Terser.minify(viewerFiles, options)).code  );  fs.writeFileSync(    dir + "/build/pdf.min.js",    (await Terser.minify(pdfFile, options)).code  );  fs.writeFileSync(    dir + "/build/pdf.worker.min.js",    (await Terser.minify(pdfWorkerFile, options)).code  );  fs.writeFileSync(    dir + "/build/pdf.sandbox.min.js",    (await Terser.minify(pdfSandboxFile, options)).code  );  fs.writeFileSync(    dir + "image_decoders/pdf.image_decoders.min.js",    (await Terser.minify(pdfImageDecodersFile, options)).code  );  console.log();  console.log("### Cleaning js files");  fs.unlinkSync(dir + "/web/viewer.js");  fs.unlinkSync(dir + "/web/debugger.js");  fs.unlinkSync(dir + "/build/pdf.js");  fs.unlinkSync(dir + "/build/pdf.worker.js");  fs.unlinkSync(dir + "/build/pdf.sandbox.js");  fs.renameSync(dir + "/build/pdf.min.js", dir + "/build/pdf.js");  fs.renameSync(dir + "/build/pdf.worker.min.js", dir + "/build/pdf.worker.js");  fs.renameSync(    dir + "/build/pdf.sandbox.min.js",    dir + "/build/pdf.sandbox.js"  );  fs.renameSync(    dir + "/image_decoders/pdf.image_decoders.min.js",    dir + "/image_decoders/pdf.image_decoders.js"  );}gulp.task(  "minified",  gulp.series(    createBuildNumber,    "locale",    function scriptingMinified() {      const defines = builder.merge(DEFINES, { MINIFIED: true, GENERIC: true });      return merge([        buildDefaultPreferences(defines, "minified/"),        createTemporaryScriptingBundle(defines),      ]);    },    function createMinified() {      console.log();      console.log("### Creating minified viewer");      const defines = builder.merge(DEFINES, { MINIFIED: true, GENERIC: true });      return buildMinified(defines, MINIFIED_DIR);    },    async function compressMinified(done) {      await parseMinified(MINIFIED_DIR);      done();    }  ));gulp.task(  "minified-legacy",  gulp.series(    createBuildNumber,    "locale",    function scriptingMinifiedLegacy() {      const defines = builder.merge(DEFINES, {        MINIFIED: true,        GENERIC: true,        SKIP_BABEL: false,      });      return merge([        buildDefaultPreferences(defines, "minified-legacy/"),        createTemporaryScriptingBundle(defines),      ]);    },    function createMinifiedLegacy() {      console.log();      console.log("### Creating minified (legacy) viewer");      const defines = builder.merge(DEFINES, {        MINIFIED: true,        GENERIC: true,        SKIP_BABEL: false,      });      return buildMinified(defines, MINIFIED_LEGACY_DIR);    },    async function compressMinifiedLegacy(done) {      await parseMinified(MINIFIED_LEGACY_DIR);      done();    }  ));function preprocessDefaultPreferences(content) {  const preprocessor2 = require("./external/builder/preprocessor2.js");  const licenseHeader = fs.readFileSync("./src/license_header.js").toString();  const GLOBALS = "/* eslint-disable */\n";  const MODIFICATION_WARNING =    "//\n// THIS FILE IS GENERATED AUTOMATICALLY, DO NOT EDIT MANUALLY!\n//\n";  const bundleDefines = builder.merge(DEFINES, {    DEFAULT_PREFERENCES: getDefaultPreferences("mozcentral/"),  });  content = preprocessor2.preprocessPDFJSCode(    {      rootPath: __dirname,      defines: bundleDefines,    },    content  );  return (    licenseHeader +    "\n" +    GLOBALS +    "\n" +    MODIFICATION_WARNING +    "\n" +    content +    "\n"  );}gulp.task(  "mozcentral",  gulp.series(    createBuildNumber,    function scriptingMozcentral() {      const defines = builder.merge(DEFINES, { MOZCENTRAL: true });      return buildDefaultPreferences(defines, "mozcentral/");    },    function createMozcentral() {      console.log();      console.log("### Building mozilla-central extension");      const defines = builder.merge(DEFINES, { MOZCENTRAL: true });      const MOZCENTRAL_DIR = BUILD_DIR + "mozcentral/",        MOZCENTRAL_EXTENSION_DIR = MOZCENTRAL_DIR + "browser/extensions/pdfjs/",        MOZCENTRAL_CONTENT_DIR = MOZCENTRAL_EXTENSION_DIR + "content/",        MOZCENTRAL_L10N_DIR =          MOZCENTRAL_DIR + "browser/locales/en-US/pdfviewer/",        FIREFOX_CONTENT_DIR = EXTENSION_SRC_DIR + "/firefox/content/";      const MOZCENTRAL_WEB_FILES = [        ...COMMON_WEB_FILES,        "!web/images/toolbarButton-openFile.svg",      ];      // Clear out everything in the firefox extension build directory      rimraf.sync(MOZCENTRAL_DIR);      return merge([        createMainBundle(defines).pipe(          gulp.dest(MOZCENTRAL_CONTENT_DIR + "build")        ),        createScriptingBundle(defines).pipe(          gulp.dest(MOZCENTRAL_CONTENT_DIR + "build")        ),        createSandboxExternal(defines).pipe(          gulp.dest(MOZCENTRAL_CONTENT_DIR + "build")        ),        createWorkerBundle(defines).pipe(          gulp.dest(MOZCENTRAL_CONTENT_DIR + "build")        ),        createWebBundle(defines, { defaultPreferencesDir: "mozcentral/" }).pipe(          gulp.dest(MOZCENTRAL_CONTENT_DIR + "web")        ),        createGVWebBundle(defines, {          defaultPreferencesDir: "mozcentral/",        }).pipe(gulp.dest(MOZCENTRAL_CONTENT_DIR + "web")),        gulp          .src(MOZCENTRAL_WEB_FILES, { base: "web/" })          .pipe(gulp.dest(MOZCENTRAL_CONTENT_DIR + "web")),        createCMapBundle().pipe(          gulp.dest(MOZCENTRAL_CONTENT_DIR + "web/cmaps")        ),        createStandardFontBundle().pipe(          gulp.dest(MOZCENTRAL_CONTENT_DIR + "web/standard_fonts")        ),        preprocessHTML("web/viewer.html", defines).pipe(          gulp.dest(MOZCENTRAL_CONTENT_DIR + "web")        ),        preprocessHTML("web/viewer-geckoview.html", defines).pipe(          gulp.dest(MOZCENTRAL_CONTENT_DIR + "web")        ),        preprocessCSS("web/viewer.css", defines)          .pipe(            postcss([              autoprefixer({                overrideBrowserslist: ["last 1 firefox versions"],              }),            ])          )          .pipe(gulp.dest(MOZCENTRAL_CONTENT_DIR + "web")),        preprocessCSS("web/viewer-geckoview.css", defines)          .pipe(            postcss([              autoprefixer({                overrideBrowserslist: ["last 1 firefox versions"],              }),            ])          )          .pipe(gulp.dest(MOZCENTRAL_CONTENT_DIR + "web")),        gulp          .src("l10n/en-US/*.properties")          .pipe(gulp.dest(MOZCENTRAL_L10N_DIR)),        gulp.src("LICENSE").pipe(gulp.dest(MOZCENTRAL_EXTENSION_DIR)),        gulp          .src(FIREFOX_CONTENT_DIR + "PdfJsDefaultPreferences.jsm")          .pipe(transform("utf8", preprocessDefaultPreferences))          .pipe(gulp.dest(MOZCENTRAL_CONTENT_DIR)),      ]);    }  ));gulp.task(  "chromium",  gulp.series(    createBuildNumber,    "locale",    function scriptingChromium() {      const defines = builder.merge(DEFINES, {        CHROME: true,        SKIP_BABEL: false,      });      return merge([        buildDefaultPreferences(defines, "chromium/"),        createTemporaryScriptingBundle(defines),      ]);    },    function createChromium() {      console.log();      console.log("### Building Chromium extension");      const defines = builder.merge(DEFINES, {        CHROME: true,        SKIP_BABEL: false,      });      const CHROME_BUILD_DIR = BUILD_DIR + "/chromium/",        CHROME_BUILD_CONTENT_DIR = CHROME_BUILD_DIR + "/content/";      const CHROME_WEB_FILES = [        ...COMMON_WEB_FILES,        "!web/images/toolbarButton-openFile.svg",      ];      // Clear out everything in the chrome extension build directory      rimraf.sync(CHROME_BUILD_DIR);      const version = getVersionJSON().version;      return merge([        createMainBundle(defines).pipe(          gulp.dest(CHROME_BUILD_CONTENT_DIR + "build")        ),        createWorkerBundle(defines).pipe(          gulp.dest(CHROME_BUILD_CONTENT_DIR + "build")        ),        createSandboxBundle(defines).pipe(          gulp.dest(CHROME_BUILD_CONTENT_DIR + "build")        ),        createWebBundle(defines, { defaultPreferencesDir: "chromium/" }).pipe(          gulp.dest(CHROME_BUILD_CONTENT_DIR + "web")        ),        gulp          .src(CHROME_WEB_FILES, { base: "web/" })          .pipe(gulp.dest(CHROME_BUILD_CONTENT_DIR + "web")),        gulp          .src(            ["web/locale/*/viewer.properties", "web/locale/locale.properties"],            { base: "web/" }          )          .pipe(gulp.dest(CHROME_BUILD_CONTENT_DIR + "web")),        createCMapBundle().pipe(          gulp.dest(CHROME_BUILD_CONTENT_DIR + "web/cmaps")        ),        createStandardFontBundle().pipe(          gulp.dest(CHROME_BUILD_CONTENT_DIR + "web/standard_fonts")        ),        preprocessHTML("web/viewer.html", defines).pipe(          gulp.dest(CHROME_BUILD_CONTENT_DIR + "web")        ),        preprocessCSS("web/viewer.css", defines)          .pipe(            postcss([              postcssLogical({ preserve: true }),              postcssDirPseudoClass(),              autoprefixer({ overrideBrowserslist: ["Chrome >= 85"] }),            ])          )          .pipe(gulp.dest(CHROME_BUILD_CONTENT_DIR + "web")),        gulp.src("LICENSE").pipe(gulp.dest(CHROME_BUILD_DIR)),        gulp          .src("extensions/chromium/manifest.json")          .pipe(replace(/\bPDFJSSCRIPT_VERSION\b/g, version))          .pipe(gulp.dest(CHROME_BUILD_DIR)),        gulp          .src(            [              "extensions/chromium/**/*.{html,js,css,png}",              "extensions/chromium/preferences_schema.json",            ],            { base: "extensions/chromium/" }          )          .pipe(gulp.dest(CHROME_BUILD_DIR)),      ]);    }  ));gulp.task("jsdoc", function (done) {  console.log();  console.log("### Generating documentation (JSDoc)");  const JSDOC_FILES = ["src/display/api.js"];  rimraf(JSDOC_BUILD_DIR, function () {    mkdirp(JSDOC_BUILD_DIR).then(function () {      const command =        '"node_modules/.bin/jsdoc" -d ' +        JSDOC_BUILD_DIR +        " " +        JSDOC_FILES.join(" ");      exec(command, done);    });  });});gulp.task("types", function (done) {  console.log("### Generating TypeScript definitions using `tsc`");  const args = [    "target ESNext",    "allowJS",    "declaration",    `outDir ${TYPES_DIR}`,    "strict",    "esModuleInterop",    "forceConsistentCasingInFileNames",    "emitDeclarationOnly",    "moduleResolution node",  ].join(" --");  exec(    `"node_modules/.bin/tsc" --${args} src/pdf.js web/pdf_viewer.component.js`,    done  );});function buildLibHelper(bundleDefines, inputStream, outputDir) {  // When we create a bundle, webpack is run on the source and it will replace  // require with __webpack_require__. When we want to use the real require,  // __non_webpack_require__ has to be used.  // In this target, we don't create a bundle, so we have to replace the  // occurrences of __non_webpack_require__ ourselves.  function babelPluginReplaceNonWebpackImports(babel) {    return {      visitor: {        Identifier(curPath, state) {          if (curPath.node.name === "__non_webpack_require__") {            curPath.replaceWith(babel.types.identifier("require"));          } else if (curPath.node.name === "__non_webpack_import__") {            curPath.replaceWith(babel.types.identifier("import"));          }        },      },    };  }  function preprocess(content) {    const skipBabel =      bundleDefines.SKIP_BABEL || /\/\*\s*no-babel-preset\s*\*\//.test(content);    content = preprocessor2.preprocessPDFJSCode(ctx, content);    content = babel.transform(content, {      sourceType: "module",      presets: skipBabel ? undefined : ["@babel/preset-env"],      plugins: [        "@babel/plugin-transform-modules-commonjs",        babelPluginReplaceNonWebpackImports,      ],      targets: BABEL_TARGETS,    }).code;    const removeCjsSrc =      /^(var\s+\w+\s*=\s*(_interopRequireDefault\()?require\(".*?)(?:\/src)(\/[^"]*"\)\)?;)$/gm;    content = content.replace(removeCjsSrc, (all, prefix, interop, suffix) => {      return prefix + suffix;    });    return licenseHeaderLibre + content;  }  const babel = require("@babel/core");  const ctx = {    rootPath: __dirname,    saveComments: false,    defines: bundleDefines,    map: {      "pdfjs-lib": "../pdf",      "pdfjs-fitCurve": "./fit_curve",    },  };  const licenseHeaderLibre = fs    .readFileSync("./src/license_header_libre.js")    .toString();  const preprocessor2 = require("./external/builder/preprocessor2.js");  return inputStream    .pipe(transform("utf8", preprocess))    .pipe(gulp.dest(outputDir));}function buildLib(defines, dir) {  const versionInfo = getVersionJSON();  const bundleDefines = builder.merge(defines, {    BUNDLE_VERSION: versionInfo.version,    BUNDLE_BUILD: versionInfo.commit,    TESTING:      defines.TESTING !== undefined        ? defines.TESTING        : process.env.TESTING === "true",    DEFAULT_PREFERENCES: getDefaultPreferences(      defines.SKIP_BABEL ? "lib/" : "lib-legacy/"    ),    DIALOG_POLYFILL_CSS:      defines.GENERIC && !defines.SKIP_BABEL ? getDialogPolyfillCSS() : "",  });  const inputStream = merge([    gulp.src(      [        "src/{core,display,shared}/**/*.js",        "!src/shared/{cffStandardStrings,fonts_utils}.js",        "src/{pdf,pdf.worker}.js",      ],      { base: "src/" }    ),    gulp.src(      ["examples/node/domstubs.js", "web/*.js", "!web/{pdfjs,viewer}.js"],      { base: "." }    ),    gulp.src("test/unit/*.js", { base: "." }),  ]);  return buildLibHelper(bundleDefines, inputStream, dir);}gulp.task(  "lib",  gulp.series(    createBuildNumber,    function scriptingLib() {      const defines = builder.merge(DEFINES, { GENERIC: true, LIB: true });      return merge([        buildDefaultPreferences(defines, "lib/"),        createTemporaryScriptingBundle(defines),      ]);    },    function createLib() {      const defines = builder.merge(DEFINES, { GENERIC: true, LIB: true });      return merge([        buildLib(defines, "build/lib/"),        createSandboxBundle(defines).pipe(gulp.dest("build/lib/")),      ]);    }  ));gulp.task(  "lib-legacy",  gulp.series(    createBuildNumber,    function scriptingLibLegacy() {      const defines = builder.merge(DEFINES, {        GENERIC: true,        LIB: true,        SKIP_BABEL: false,      });      return merge([        buildDefaultPreferences(defines, "lib-legacy/"),        createTemporaryScriptingBundle(defines),      ]);    },    function createLibLegacy() {      const defines = builder.merge(DEFINES, {        GENERIC: true,        LIB: true,        SKIP_BABEL: false,      });      return merge([        buildLib(defines, "build/lib-legacy/"),        createSandboxBundle(defines).pipe(gulp.dest("build/lib-legacy/")),      ]);    }  ));function compressPublish(targetName, dir) {  return gulp    .src(dir + "**")    .pipe(zip(targetName))    .pipe(gulp.dest(BUILD_DIR))    .on("end", function () {      console.log("Built distribution file: " + targetName);    });}gulp.task(  "publish",  gulp.series("generic", "generic-legacy", function createPublish(done) {    const version = JSON.parse(      fs.readFileSync(BUILD_DIR + "version.json").toString()    ).version;    config.stableVersion = version;    return merge([      createStringSource(CONFIG_FILE, JSON.stringify(config, null, 2)).pipe(        gulp.dest(".")      ),      compressPublish("pdfjs-" + version + "-dist.zip", GENERIC_DIR),      compressPublish(        "pdfjs-" + version + "-legacy-dist.zip",        GENERIC_LEGACY_DIR      ),    ]);  }));function setTestEnv(done) {  process.env.TESTING = "true";  // TODO: Re-write the relevant unit-tests, which are using `new Date(...)`,  //       to not required the following time-zone hack since it doesn't work  //       when the unit-tests are run directly in the browser.  process.env.TZ = "UTC";  done();}gulp.task("dev-fitCurve", function createDevFitCurve() {  console.log();  console.log("### Building development fitCurve");  const defines = builder.merge(DEFINES, { GENERIC: true, TESTING: true });  const fitCurveDir = BUILD_DIR + "dev-fitCurve/";  rimraf.sync(fitCurveDir);  return createFitCurveBundle(defines).pipe(gulp.dest(fitCurveDir));});gulp.task(  "test",  gulp.series(    setTestEnv,    "generic",    "components",    "dev-fitCurve",    function runTest() {      return streamqueue(        { objectMode: true },        createTestSource("unit"),        createTestSource("browser"),        createTestSource("integration")      );    }  ));gulp.task(  "bottest",  gulp.series(    setTestEnv,    "generic",    "components",    "dev-fitCurve",    function runBotTest() {      return streamqueue(        { objectMode: true },        createTestSource("unit", { bot: true }),        createTestSource("font", { bot: true }),        createTestSource("browser", { bot: true }),        createTestSource("integration")      );    }  ));gulp.task(  "xfatest",  gulp.series(    setTestEnv,    "generic",    "components",    "dev-fitCurve",    function runXfaTest() {      return streamqueue(        { objectMode: true },        createTestSource("unit"),        createTestSource("browser", { xfaOnly: true }),        createTestSource("integration")      );    }  ));gulp.task(  "botxfatest",  gulp.series(    setTestEnv,    "generic",    "components",    "dev-fitCurve",    function runBotXfaTest() {      return streamqueue(        { objectMode: true },        createTestSource("unit", { bot: true }),        createTestSource("font", { bot: true }),        createTestSource("browser", { bot: true, xfaOnly: true }),        createTestSource("integration")      );    }  ));gulp.task(  "browsertest",  gulp.series(setTestEnv, "generic", "components", function runBrowserTest() {    return createTestSource("browser");  }));gulp.task(  "botbrowsertest",  gulp.series(    setTestEnv,    "generic",    "components",    function runBotBrowserTest() {      return streamqueue(        { objectMode: true },        createTestSource("browser", { bot: true })      );    }  ));gulp.task(  "unittest",  gulp.series(setTestEnv, "generic", "dev-fitCurve", function runUnitTest() {    return createTestSource("unit");  }));gulp.task(  "integrationtest",  gulp.series(setTestEnv, "generic", function runIntegrationTest() {    return createTestSource("integration");  }));gulp.task(  "fonttest",  gulp.series(setTestEnv, function runFontTest() {    return createTestSource("font");  }));gulp.task(  "makeref",  gulp.series(setTestEnv, "generic", "components", function runMakeref(done) {    makeRef(done);  }));gulp.task(  "botmakeref",  gulp.series(    setTestEnv,    "generic",    "components",    function runBotMakeref(done) {      makeRef(done, true);    }  ));gulp.task(  "typestest",  gulp.series(    setTestEnv,    "generic",    "types",    function createTypesTest() {      return merge([        packageJson().pipe(gulp.dest(TYPESTEST_DIR)),        gulp          .src([            GENERIC_DIR + "build/pdf.js",            GENERIC_DIR + "build/pdf.worker.js",            SRC_DIR + "pdf.worker.entry.js",          ])          .pipe(gulp.dest(TYPESTEST_DIR + "build/")),        gulp          .src(TYPES_DIR + "**/*", { base: TYPES_DIR })          .pipe(gulp.dest(TYPESTEST_DIR + "types/")),      ]);    },    function runTypesTest(done) {      exec('"node_modules/.bin/tsc" -p test/types', function (err, stdout) {        if (err) {          console.log(`Couldn't compile TypeScript test: ${stdout}`);        }        done(err);      });    }  ));function createBaseline(done) {  console.log();  console.log("### Creating baseline environment");  const baselineCommit = process.env.BASELINE;  if (!baselineCommit) {    done(new Error("Missing baseline commit. Specify the BASELINE variable."));    return;  }  let initializeCommand = "git fetch origin";  if (!checkDir(BASELINE_DIR)) {    mkdirp.sync(BASELINE_DIR);    initializeCommand = "git clone ../../ .";  }  const workingDirectory = path.resolve(process.cwd(), BASELINE_DIR);  exec(initializeCommand, { cwd: workingDirectory }, function (error) {    if (error) {      done(new Error("Baseline clone/fetch failed."));      return;    }    exec(      "git checkout " + baselineCommit,      { cwd: workingDirectory },      function (error2) {        if (error2) {          done(new Error("Baseline commit checkout failed."));          return;        }        console.log('Baseline commit "' + baselineCommit + '" checked out.');        done();      }    );  });}gulp.task(  "unittestcli",  gulp.series(setTestEnv, "lib-legacy", function runUnitTestCli(done) {    const options = [      "node_modules/jasmine/bin/jasmine",      "JASMINE_CONFIG_PATH=test/unit/clitests.json",    ];    const jasmineProcess = startNode(options, { stdio: "inherit" });    jasmineProcess.on("close", function (code) {      if (code !== 0) {        done(new Error("Unit tests failed."));        return;      }      done();    });  }));gulp.task("lint", function (done) {  console.log();  console.log("### Linting JS/CSS files");  // Ensure that we lint the Firefox specific *.jsm files too.  const esLintOptions = [    "node_modules/eslint/bin/eslint",    "--ext",    ".js,.jsm,.json",    ".",    "--report-unused-disable-directives",  ];  if (process.argv.includes("--fix")) {    esLintOptions.push("--fix");  }  const styleLintOptions = [    "node_modules/stylelint/bin/stylelint",    "**/*.css",    "--report-needless-disables",  ];  if (process.argv.includes("--fix")) {    styleLintOptions.push("--fix");  }  const esLintProcess = startNode(esLintOptions, { stdio: "inherit" });  esLintProcess.on("close", function (esLintCode) {    if (esLintCode !== 0) {      done(new Error("ESLint failed."));      return;    }    const styleLintProcess = startNode(styleLintOptions, { stdio: "inherit" });    styleLintProcess.on("close", function (styleLintCode) {      if (styleLintCode !== 0) {        done(new Error("Stylelint failed."));        return;      }      console.log("files checked, no errors found");      done();    });  });});gulp.task(  "lint-chromium",  gulp.series(    function scriptingLintChromium() {      const defines = builder.merge(DEFINES, {        CHROME: true,        SKIP_BABEL: false,        TESTING: false,      });      return buildDefaultPreferences(defines, "lint-chromium/");    },    function runLintChromium(done) {      console.log();      console.log("### Checking supplemental Chromium files");      if (        !checkChromePreferencesFile(          "extensions/chromium/preferences_schema.json",          getDefaultPreferences("lint-chromium/")        )      ) {        done(new Error("chromium/preferences_schema is not in sync."));        return;      }      done();    }  ));gulp.task("dev-css", function createDevCSS() {  console.log();  console.log("### Building development CSS");  const defines = builder.merge(DEFINES, { GENERIC: true, TESTING: true });  const cssDir = BUILD_DIR + "dev-css/";  return merge([    gulp.src("web/images/*", { base: "web/" }).pipe(gulp.dest(cssDir)),    preprocessCSS("web/viewer.css", defines)      .pipe(        postcss([          postcssLogical({ preserve: true }),          postcssDirPseudoClass(),          autoprefixer({ overrideBrowserslist: ["last 1 versions"] }),        ])      )      .pipe(gulp.dest(cssDir)),  ]);});gulp.task(  "dev-sandbox",  gulp.series(    function scriptingDevSandbox() {      const defines = builder.merge(DEFINES, { GENERIC: true, TESTING: true });      return createTemporaryScriptingBundle(defines, {        disableVersionInfo: true,      });    },    function createDevSandbox() {      console.log();      console.log("### Building development sandbox");      const defines = builder.merge(DEFINES, { GENERIC: true, TESTING: true });      const sandboxDir = BUILD_DIR + "dev-sandbox/";      rimraf.sync(sandboxDir);      return createSandboxBundle(defines, {        disableVersionInfo: true,      }).pipe(gulp.dest(sandboxDir));    }  ));gulp.task(  "server",  gulp.parallel(    function watchDevCSS() {      gulp.watch(        ["web/*.css", "web/images/*"],        { ignoreInitial: false },        gulp.series("dev-css")      );    },    function watchDevFitCurve() {      gulp.watch(        ["src/display/editor/*"],        { ignoreInitial: false },        gulp.series("dev-fitCurve")      );    },    function watchDevSandbox() {      gulp.watch(        [          "src/pdf.{sandbox,sandbox.external,scripting}.js",          "src/scripting_api/*.js",          "src/shared/scripting_utils.js",          "external/quickjs/*.js",        ],        { ignoreInitial: false },        gulp.series("dev-sandbox")      );    },    function createServer() {      console.log();      console.log("### Starting local server");      const WebServer = require("./test/webserver.js").WebServer;      const server = new WebServer();      server.port = 8888;      server.start();    }  ));gulp.task("clean", function (done) {  console.log();  console.log("### Cleaning up project builds");  rimraf(BUILD_DIR, done);});gulp.task("importl10n", function (done) {  const locales = require("./external/importL10n/locales.js");  console.log();  console.log("### Importing translations from mozilla-central");  if (!fs.existsSync(L10N_DIR)) {    fs.mkdirSync(L10N_DIR);  }  locales.downloadL10n(L10N_DIR, done);});function ghPagesPrepare() {  console.log();  console.log("### Creating web site");  rimraf.sync(GH_PAGES_DIR);  // 'vfs' because web/viewer.html needs its BOM.  return merge([    vfs      .src(GENERIC_DIR + "**/*", { base: GENERIC_DIR, stripBOM: false })      .pipe(gulp.dest(GH_PAGES_DIR)),    vfs      .src(GENERIC_LEGACY_DIR + "**/*", {        base: GENERIC_LEGACY_DIR,        stripBOM: false,      })      .pipe(gulp.dest(GH_PAGES_DIR + "legacy/")),    gulp      .src(JSDOC_BUILD_DIR + "**/*", { base: JSDOC_BUILD_DIR })      .pipe(gulp.dest(GH_PAGES_DIR + "api/draft/")),  ]);}gulp.task("wintersmith", function (done) {  const wintersmith = require("wintersmith");  const env = wintersmith("docs/config.json");  env.build(GH_PAGES_DIR, function (error) {    if (error) {      done(error);      return;    }    replaceInFile(      GH_PAGES_DIR + "/getting_started/index.html",      /STABLE_VERSION/g,      config.stableVersion    );    console.log("Done building with wintersmith.");    done();  });});function ghPagesGit(done) {  const VERSION = getVersionJSON().version;  const reason = process.env.PDFJS_UPDATE_REASON;  safeSpawnSync("git", ["init"], { cwd: GH_PAGES_DIR });  safeSpawnSync("git", ["remote", "add", "origin", REPO], {    cwd: GH_PAGES_DIR,  });  safeSpawnSync("git", ["add", "-A"], { cwd: GH_PAGES_DIR });  safeSpawnSync(    "git",    [      "commit",      "-am",      "gh-pages site created via gulpfile.js script",      "-m",      "PDF.js version " + VERSION + (reason ? " - " + reason : ""),    ],    { cwd: GH_PAGES_DIR }  );  safeSpawnSync("git", ["branch", "-m", "gh-pages"], { cwd: GH_PAGES_DIR });  console.log();  console.log("Website built in " + GH_PAGES_DIR);  done();}gulp.task(  "web",  gulp.series(    "generic",    "generic-legacy",    "jsdoc",    ghPagesPrepare,    "wintersmith",    ghPagesGit  ));function packageJson() {  const VERSION = getVersionJSON().version;  const DIST_NAME = "pdfjs-dist";  const DIST_DESCRIPTION = "Generic build of Mozilla's PDF.js library.";  const DIST_KEYWORDS = ["Mozilla", "pdf", "pdf.js"];  const DIST_HOMEPAGE = "http://mozilla.github.io/pdf.js/";  const DIST_BUGS_URL = "https://github.com/mozilla/pdf.js/issues";  const DIST_LICENSE = "Apache-2.0";  const npmManifest = {    name: DIST_NAME,    version: VERSION,    main: "build/pdf.js",    types: "types/src/pdf.d.ts",    description: DIST_DESCRIPTION,    keywords: DIST_KEYWORDS,    homepage: DIST_HOMEPAGE,    bugs: DIST_BUGS_URL,    license: DIST_LICENSE,    optionalDependencies: {      canvas: "^2.11.0",    },    dependencies: {      "web-streams-polyfill": "^3.2.1",    },    browser: {      canvas: false,      fs: false,      http: false,      https: false,      url: false,      zlib: false,    },    format: "amd", // to not allow system.js to choose 'cjs'    repository: {      type: "git",      url: DIST_REPO_URL,    },  };  return createStringSource(    "package.json",    JSON.stringify(npmManifest, null, 2)  );}gulp.task(  "dist-pre",  gulp.series(    "generic",    "generic-legacy",    "components",    "components-legacy",    "image_decoders",    "image_decoders-legacy",    "lib",    "minified",    "minified-legacy",    "types",    function createDist() {      console.log();      console.log("### Cloning baseline distribution");      rimraf.sync(DIST_DIR);      mkdirp.sync(DIST_DIR);      safeSpawnSync("git", ["clone", "--depth", "1", DIST_REPO_URL, DIST_DIR]);      console.log();      console.log("### Overwriting all files");      rimraf.sync(path.join(DIST_DIR, "*"));      return merge([        packageJson().pipe(gulp.dest(DIST_DIR)),        vfs          .src("external/dist/**/*", { base: "external/dist", stripBOM: false })          .pipe(gulp.dest(DIST_DIR)),        gulp.src(GENERIC_DIR + "LICENSE").pipe(gulp.dest(DIST_DIR)),        gulp          .src(GENERIC_DIR + "web/cmaps/**/*", { base: GENERIC_DIR + "web" })          .pipe(gulp.dest(DIST_DIR)),        gulp          .src(GENERIC_DIR + "web/standard_fonts/**/*", {            base: GENERIC_DIR + "web",          })          .pipe(gulp.dest(DIST_DIR)),        gulp          .src([            GENERIC_DIR + "build/{pdf,pdf.worker,pdf.sandbox}.js",            GENERIC_DIR + "build/{pdf,pdf.worker,pdf.sandbox}.js.map",            SRC_DIR + "pdf.worker.entry.js",          ])          .pipe(gulp.dest(DIST_DIR + "build/")),        gulp          .src([            GENERIC_LEGACY_DIR + "build/{pdf,pdf.worker,pdf.sandbox}.js",            GENERIC_LEGACY_DIR + "build/{pdf,pdf.worker,pdf.sandbox}.js.map",            SRC_DIR + "pdf.worker.entry.js",          ])          .pipe(gulp.dest(DIST_DIR + "legacy/build/")),        gulp          .src(MINIFIED_DIR + "build/pdf.js")          .pipe(rename("pdf.min.js"))          .pipe(gulp.dest(DIST_DIR + "build/")),        gulp          .src(MINIFIED_DIR + "build/pdf.worker.js")          .pipe(rename("pdf.worker.min.js"))          .pipe(gulp.dest(DIST_DIR + "build/")),        gulp          .src(MINIFIED_DIR + "build/pdf.sandbox.js")          .pipe(rename("pdf.sandbox.min.js"))          .pipe(gulp.dest(DIST_DIR + "build/")),        gulp          .src(MINIFIED_DIR + "image_decoders/pdf.image_decoders.js")          .pipe(rename("pdf.image_decoders.min.js"))          .pipe(gulp.dest(DIST_DIR + "image_decoders/")),        gulp          .src(MINIFIED_LEGACY_DIR + "build/pdf.js")          .pipe(rename("pdf.min.js"))          .pipe(gulp.dest(DIST_DIR + "legacy/build/")),        gulp          .src(MINIFIED_LEGACY_DIR + "build/pdf.worker.js")          .pipe(rename("pdf.worker.min.js"))          .pipe(gulp.dest(DIST_DIR + "legacy/build/")),        gulp          .src(MINIFIED_LEGACY_DIR + "build/pdf.sandbox.js")          .pipe(rename("pdf.sandbox.min.js"))          .pipe(gulp.dest(DIST_DIR + "legacy/build/")),        gulp          .src(MINIFIED_LEGACY_DIR + "image_decoders/pdf.image_decoders.js")          .pipe(rename("pdf.image_decoders.min.js"))          .pipe(gulp.dest(DIST_DIR + "legacy/image_decoders/")),        gulp          .src(COMPONENTS_DIR + "**/*", { base: COMPONENTS_DIR })          .pipe(gulp.dest(DIST_DIR + "web/")),        gulp          .src(COMPONENTS_LEGACY_DIR + "**/*", { base: COMPONENTS_LEGACY_DIR })          .pipe(gulp.dest(DIST_DIR + "legacy/web/")),        gulp          .src(IMAGE_DECODERS_DIR + "**/*", { base: IMAGE_DECODERS_DIR })          .pipe(gulp.dest(DIST_DIR + "image_decoders/")),        gulp          .src(IMAGE_DECODERS_LEGACY_DIR + "**/*", {            base: IMAGE_DECODERS_LEGACY_DIR,          })          .pipe(gulp.dest(DIST_DIR + "legacy/image_decoders/")),        gulp          .src(LIB_DIR + "**/*", { base: LIB_DIR })          .pipe(gulp.dest(DIST_DIR + "lib/")),        gulp          .src(TYPES_DIR + "**/*", { base: TYPES_DIR })          .pipe(gulp.dest(DIST_DIR + "types/")),      ]);    }  ));gulp.task(  "dist-install",  gulp.series("dist-pre", function createDistInstall(done) {    let distPath = DIST_DIR;    const opts = {};    const installPath = process.env.PDFJS_INSTALL_PATH;    if (installPath) {      opts.cwd = installPath;      distPath = path.relative(installPath, distPath);    }    safeSpawnSync("npm", ["install", distPath], opts);    done();  }));gulp.task(  "dist",  gulp.series("dist-pre", function createDist(done) {    const VERSION = getVersionJSON().version;    console.log();    console.log("### Committing changes");    let reason = process.env.PDFJS_UPDATE_REASON;    // Attempt to work-around the broken link, see https://github.com/mozilla/pdf.js/issues/10391    if (typeof reason === "string") {      const reasonParts =        /^(See )(mozilla\/pdf\.js)@tags\/(v\d+\.\d+\.\d+)\s*$/.exec(reason);      if (reasonParts) {        reason =          reasonParts[1] +          "https://github.com/" +          reasonParts[2] +          "/releases/tag/" +          reasonParts[3];      }    }    const message =      "PDF.js version " + VERSION + (reason ? " - " + reason : "");    safeSpawnSync("git", ["add", "*"], { cwd: DIST_DIR });    safeSpawnSync("git", ["commit", "-am", message], { cwd: DIST_DIR });    safeSpawnSync("git", ["tag", "-a", "v" + VERSION, "-m", message], {      cwd: DIST_DIR,    });    console.log();    console.log("Done. Push with");    console.log(      "  cd " + DIST_DIR + "; git push --tags " + DIST_REPO_URL + " master"    );    console.log();    done();  }));gulp.task(  "mozcentralbaseline",  gulp.series(createBaseline, function createMozcentralBaseline(done) {    console.log();    console.log("### Creating mozcentral baseline environment");    // Create a mozcentral build.    rimraf.sync(BASELINE_DIR + BUILD_DIR);    const workingDirectory = path.resolve(process.cwd(), BASELINE_DIR);    safeSpawnSync("gulp", ["mozcentral"], {      env: process.env,      cwd: workingDirectory,      stdio: "inherit",    });    // Copy the mozcentral build to the mozcentral baseline directory.    rimraf.sync(MOZCENTRAL_BASELINE_DIR);    mkdirp.sync(MOZCENTRAL_BASELINE_DIR);    gulp      .src([BASELINE_DIR + BUILD_DIR + "mozcentral/**/*"])      .pipe(gulp.dest(MOZCENTRAL_BASELINE_DIR))      .on("end", function () {        // Commit the mozcentral baseline.        safeSpawnSync("git", ["init"], { cwd: MOZCENTRAL_BASELINE_DIR });        safeSpawnSync("git", ["add", "."], { cwd: MOZCENTRAL_BASELINE_DIR });        safeSpawnSync("git", ["commit", "-m", '"mozcentral baseline"'], {          cwd: MOZCENTRAL_BASELINE_DIR,        });        done();      });  }));gulp.task(  "mozcentraldiff",  gulp.series(    "mozcentral",    "mozcentralbaseline",    function createMozcentralDiff(done) {      console.log();      console.log("### Creating mozcentral diff");      // Create the diff between the current mozcentral build and the      // baseline mozcentral build, which both exist at this point.      // The mozcentral baseline directory is a Git repository, so we      // remove all files and copy the current mozcentral build files      // into it to create the diff.      rimraf.sync(MOZCENTRAL_BASELINE_DIR + "*");      gulp        .src([BUILD_DIR + "mozcentral/**/*"])        .pipe(gulp.dest(MOZCENTRAL_BASELINE_DIR))        .on("end", function () {          safeSpawnSync("git", ["add", "-A"], { cwd: MOZCENTRAL_BASELINE_DIR });          const diff = safeSpawnSync(            "git",            ["diff", "--binary", "--cached", "--unified=8"],            { cwd: MOZCENTRAL_BASELINE_DIR }          ).stdout;          createStringSource(MOZCENTRAL_DIFF_FILE, diff)            .pipe(gulp.dest(BUILD_DIR))            .on("end", function () {              console.log(                "Result diff can be found at " +                  BUILD_DIR +                  MOZCENTRAL_DIFF_FILE              );              done();            });        });    }  ));gulp.task("externaltest", function (done) {  console.log();  console.log("### Running test-fixtures.js");  safeSpawnSync("node", ["external/builder/test-fixtures.js"], {    stdio: "inherit",  });  console.log();  console.log("### Running test-fixtures_esprima.js");  safeSpawnSync("node", ["external/builder/test-fixtures_esprima.js"], {    stdio: "inherit",  });  done();});gulp.task(  "ci-test",  gulp.series(gulp.parallel("lint", "externaltest", "unittestcli"), "typestest"));
 |