fs-extra#mkdirs TypeScript Examples

The following examples show how to use fs-extra#mkdirs. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: download-ui5-resources.ts    From ui5-language-assistant with Apache License 2.0 6 votes vote down vote up
export async function addUi5Resources(
  version: TestModelVersion,
  folder: string
): Promise<void> {
  // CDN libraries (example URL):
  // https://sapui5-sapui5.dispatcher.us1.hana.ondemand.com/test-resources/sap/m/designtime/api.json
  // Older versions:
  // https://sapui5.hana.ondemand.com/1.71.14/test-resources/sap/m/designtime/api.json
  const baseUrl = `https://sapui5.hana.ondemand.com/${version}/test-resources/`;
  const libs = await getLibs(version);
  const nameToFile = zipObject(
    libs,
    map(libs, (_) => `${baseUrl}${_.replace(/\./g, "/")}/designtime/api.json`)
  );

  await mkdirs(folder);

  // Write files in parallel
  await Promise.all(
    map(nameToFile, (url, name) => {
      return writeUrlToFile(
        url,
        resolve(folder, `${name}.designtime.api.json`)
      );
    })
  );
}
Example #2
Source File: ui5-model.ts    From ui5-language-assistant with Apache License 2.0 5 votes vote down vote up
// This function is exported for testing purposes (using a mock fetcher)
export async function getSemanticModelWithFetcher(
  fetcher: Fetcher,
  modelCachePath: string | undefined
): Promise<UI5SemanticModel> {
  const version = DEFAULT_UI5_VERSION;
  getLogger().info("building UI5 semantic Model for version", { version });
  const jsonMap: Record<string, Json> = {};
  const baseUrl = `https://sapui5.hana.ondemand.com/${version}/test-resources/`;
  const suffix = "/designtime/api.json";
  const libs = getLibs();
  let cacheFolder: string | undefined;

  // Note: all cache handling (reading, writing etc) is optional from the user perspective but
  // impacts performance, therefore if any errors occur when handling the cache we ignore them but output
  // a warning to the user
  if (modelCachePath !== undefined) {
    cacheFolder = getCacheFolder(modelCachePath, version);
    getLogger().info("Caching UI5 resources in", { cacheFolder });
    try {
      await mkdirs(cacheFolder);
    } catch (err) {
      getLogger().warn("Failed creating UI5 resources cache folder`", {
        cacheFolder,
        msg: err,
      });
      cacheFolder = undefined;
    }
  }

  await Promise.all(
    map(libs, async (libName) => {
      const cacheFilePath = getCacheFilePath(cacheFolder, libName);
      let apiJson = await readFromCache(cacheFilePath);
      // If the file doesn't exist in the cache (or we couldn't read it), fetch it from the network
      if (apiJson === undefined) {
        getLogger().info("No cache found for UI5 lib", { libName });
        const url = baseUrl + libName.replace(/\./g, "/") + suffix;
        const response = await fetcher(url);
        if (response.ok) {
          apiJson = await response.json();
          await writeToCache(cacheFilePath, apiJson);
        } else {
          getLogger().error("Could not read UI5 resources from", { url });
        }
      } else {
        getLogger().info("Reading Cache For UI5 Lib ", {
          libName,
          cacheFilePath,
        });
      }
      if (apiJson !== undefined) {
        jsonMap[libName] = apiJson;
      }
    })
  );

  return generate({
    version: version,
    libraries: jsonMap,
    typeNameFix: getTypeNameFix(),
    strict: false,
    printValidationErrors: false,
  });
}
Example #3
Source File: ui5-model-spec.ts    From ui5-language-assistant with Apache License 2.0 4 votes vote down vote up
describe("the UI5 language assistant ui5 model", () => {
  // The default timeout is 2000ms and getSemanticModel can take ~3000-5000ms
  const GET_MODEL_TIMEOUT = 10000;
  const VERSION = "1.71.14";
  const NO_CACHE_FOLDER = undefined;

  function assertSemanticModel(ui5Model: UI5SemanticModel): void {
    expect(ui5Model.version).to.equal(VERSION);

    expect(Object.keys(ui5Model.classes).length).to.be.greaterThan(200);
    expect(Object.keys(ui5Model.namespaces).length).to.be.greaterThan(200);
    expect(Object.keys(ui5Model.interfaces).length).to.be.greaterThan(30);
    expect(Object.keys(ui5Model.functions).length).to.be.greaterThan(30);
    expect(Object.keys(ui5Model.enums).length).to.be.greaterThan(200);
    expect(Object.keys(ui5Model.typedefs).length).to.be.greaterThan(10);

    expect(Object.keys(ui5Model.classes)).to.include("sap.m.List");
    expect(Object.keys(ui5Model.namespaces)).to.include("sap.m");
    expect(Object.keys(ui5Model.interfaces)).to.include("sap.f.ICard");
    expect(Object.keys(ui5Model.functions)).to.include(
      "module:sap/base/assert"
    );
    expect(Object.keys(ui5Model.enums)).to.include("sap.m.ButtonType");
    expect(Object.keys(ui5Model.typedefs)).to.include("sap.ui.fl.Selector");

    // Dist layer
    expect(Object.keys(ui5Model.classes)).to.include("sap.ui.vk.Camera");
    expect(Object.keys(ui5Model.namespaces)).to.include("sap.apf.base");
    expect(Object.keys(ui5Model.enums)).to.include(
      "sap.ca.ui.charts.ChartSelectionMode"
    );
  }

  it("will get UI5 semantic model", async () => {
    const ui5Model = await getSemanticModel(NO_CACHE_FOLDER);
    assertSemanticModel(ui5Model);
  }).timeout(GET_MODEL_TIMEOUT);

  it("doesn't fail if a file cannot be fetched", async () => {
    const ui5Model = await getSemanticModelWithFetcher(async (url: string) => {
      return {
        ok: false,
        json: (): never => {
          throw new Error(`Cannot read from ${url}`);
        },
      };
    }, NO_CACHE_FOLDER);
    expect(ui5Model).to.exist;
  });

  describe("with cache", () => {
    describe("cache in temp dir", () => {
      let cachePath: string;
      beforeEach(async () => {
        ({ path: cachePath } = await tempDir());
      });

      afterEach(async () => {
        // The temp folder will contain files at the end so we remove it
        // with rimraf instead of calling cleanup()
        rimrafSync(cachePath);
      });

      it("caches the model the first time getSemanticModel is called", async () => {
        const ui5Model = await getSemanticModel(cachePath);
        assertSemanticModel(ui5Model);

        // Check the files were created in the folder
        const files = await readdir(cachePath);
        expect(files).to.not.be.empty;

        // Call getSemanticModel again with the same path and check it doesn't try to read from the URL
        let fetcherCalled = false;
        const ui5ModelFromCache = await getSemanticModelWithFetcher(
          (url: string): never => {
            fetcherCalled = true;
            throw new Error(
              `The files should be taken from the cache, got call for ${url}`
            );
          },
          cachePath
        );
        expect(fetcherCalled).to.be.false;
        // Make sure it's not the model itself that is cached
        expect(ui5ModelFromCache).to.not.equal(ui5Model);
        // Check we got the same result (we can't use deep equal so the check is shallow)
        forEach(ui5Model, (value, key) => {
          if (isPlainObject(value)) {
            expect(
              Object.keys(
                ui5ModelFromCache[key as keyof UI5SemanticModel] as Record<
                  string,
                  unknown
                >
              )
            ).to.deep.equalInAnyOrder(
              Object.keys(value as Record<string, unknown>)
            );
          }
        });
        assertSemanticModel(ui5ModelFromCache);
      }).timeout(GET_MODEL_TIMEOUT);

      it("doesn't fail when file cannot be written to the cache", async () => {
        // Create a folder with the file name so the file will not be written
        const cacheFilePath = getCacheFilePath(
          getCacheFolder(cachePath, VERSION),
          "sap.m"
        );
        expectExists(cacheFilePath, "cacheFilePath");
        await mkdirs(cacheFilePath);

        const ui5Model = await getSemanticModel(cachePath);
        expect(ui5Model).to.exist;
        // Check we still got the sap.m library data
        expect(Object.keys(ui5Model.namespaces)).to.contain("sap.m");
        expect(ui5Model.namespaces["sap.m"].library).to.equal("sap.m");
      }).timeout(GET_MODEL_TIMEOUT);

      it("doesn't fail when file cannot be read from the cache", async () => {
        // Create a file with non-json content so the file will not be deserialized
        const cacheFolder = getCacheFolder(cachePath, VERSION);
        await mkdirs(cacheFolder);
        const cacheFilePath = getCacheFilePath(cacheFolder, "sap.m");
        expectExists(cacheFilePath, "cacheFilePath");
        await writeFile(cacheFilePath, "not json");

        const ui5Model = await getSemanticModel(cachePath);
        expect(ui5Model).to.exist;
        // Check we still got the sap.m library data
        expect(Object.keys(ui5Model.namespaces)).to.contain("sap.m");
        expect(ui5Model.namespaces["sap.m"].library).to.equal("sap.m");
      }).timeout(GET_MODEL_TIMEOUT);
    });

    describe("cache path is a file", async () => {
      let cachePath: string;
      let cleanup: () => Promise<void>;
      beforeEach(async () => {
        ({ path: cachePath, cleanup } = await tempFile());
      });

      afterEach(async () => {
        await cleanup();
      });

      it("does not cache the model", async () => {
        const ui5Model = await getSemanticModel(cachePath);
        assertSemanticModel(ui5Model);

        // Call getSemanticModel again with the same path and check it doesn't try to read from the URL
        let fetcherCalled = false;
        await getSemanticModelWithFetcher(async (): Promise<FetchResponse> => {
          fetcherCalled = true;
          return {
            ok: true,
            json: async (): Promise<unknown> => {
              return {};
            },
          };
        }, cachePath);
        expect(fetcherCalled).to.be.true;
      }).timeout(GET_MODEL_TIMEOUT);
    });
  });
});