@frictionless-ts/dataset 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/build/file/copy.d.ts +4 -0
- package/build/file/copy.js +7 -0
- package/build/file/copy.spec.d.ts +1 -0
- package/build/file/copy.spec.js +104 -0
- package/build/file/describe.d.ts +7 -0
- package/build/file/describe.js +9 -0
- package/build/file/fetch.d.ts +2 -0
- package/build/file/fetch.js +21 -0
- package/build/file/index.d.ts +9 -0
- package/build/file/index.js +10 -0
- package/build/file/infer.d.ts +10 -0
- package/build/file/infer.js +48 -0
- package/build/file/infer.spec.d.ts +1 -0
- package/build/file/infer.spec.js +141 -0
- package/build/file/load.d.ts +3 -0
- package/build/file/load.js +7 -0
- package/build/file/path.d.ts +2 -0
- package/build/file/path.js +17 -0
- package/build/file/save.d.ts +3 -0
- package/build/file/save.js +7 -0
- package/build/file/temp.d.ts +11 -0
- package/build/file/temp.js +23 -0
- package/build/file/validate.d.ts +6 -0
- package/build/file/validate.js +47 -0
- package/build/file/validate.spec.d.ts +1 -0
- package/build/file/validate.spec.js +180 -0
- package/build/folder/create.d.ts +1 -0
- package/build/folder/create.js +5 -0
- package/build/folder/index.d.ts +2 -0
- package/build/folder/index.js +3 -0
- package/build/folder/temp.d.ts +3 -0
- package/build/folder/temp.js +16 -0
- package/build/index.d.ts +36 -0
- package/build/index.js +35 -0
- package/build/package/index.d.ts +2 -0
- package/build/package/index.js +3 -0
- package/build/package/merge.d.ts +23 -0
- package/build/package/merge.js +12 -0
- package/build/package/path.d.ts +3 -0
- package/build/package/path.js +43 -0
- package/build/package/path.spec.d.ts +1 -0
- package/build/package/path.spec.js +56 -0
- package/build/plugin.d.ts +11 -0
- package/build/plugin.js +2 -0
- package/build/plugins/ckan/ckan/index.d.ts +1 -0
- package/build/plugins/ckan/ckan/index.js +2 -0
- package/build/plugins/ckan/ckan/request.d.ts +11 -0
- package/build/plugins/ckan/ckan/request.js +35 -0
- package/build/plugins/ckan/index.d.ts +4 -0
- package/build/plugins/ckan/index.js +5 -0
- package/build/plugins/ckan/package/Organization.d.ts +21 -0
- package/build/plugins/ckan/package/Organization.js +2 -0
- package/build/plugins/ckan/package/Package.d.ts +76 -0
- package/build/plugins/ckan/package/Package.js +2 -0
- package/build/plugins/ckan/package/Tag.d.ts +17 -0
- package/build/plugins/ckan/package/Tag.js +2 -0
- package/build/plugins/ckan/package/convert/fromCkan.d.ts +3 -0
- package/build/plugins/ckan/package/convert/fromCkan.js +63 -0
- package/build/plugins/ckan/package/convert/fromCkan.spec.d.ts +1 -0
- package/build/plugins/ckan/package/convert/fromCkan.spec.js +80 -0
- package/build/plugins/ckan/package/convert/toCkan.d.ts +22 -0
- package/build/plugins/ckan/package/convert/toCkan.js +51 -0
- package/build/plugins/ckan/package/convert/toCkan.spec.d.ts +1 -0
- package/build/plugins/ckan/package/convert/toCkan.spec.js +153 -0
- package/build/plugins/ckan/package/fixtures/ckan-package.json +308 -0
- package/build/plugins/ckan/package/index.d.ts +7 -0
- package/build/plugins/ckan/package/index.js +5 -0
- package/build/plugins/ckan/package/load.d.ts +21 -0
- package/build/plugins/ckan/package/load.js +74 -0
- package/build/plugins/ckan/package/load.spec.d.ts +1 -0
- package/build/plugins/ckan/package/load.spec.js +11 -0
- package/build/plugins/ckan/package/save.d.ts +10 -0
- package/build/plugins/ckan/package/save.js +83 -0
- package/build/plugins/ckan/package/save.spec.d.ts +1 -0
- package/build/plugins/ckan/package/save.spec.js +319 -0
- package/build/plugins/ckan/plugin.d.ts +19 -0
- package/build/plugins/ckan/plugin.js +18 -0
- package/build/plugins/ckan/plugin.spec.d.ts +1 -0
- package/build/plugins/ckan/plugin.spec.js +83 -0
- package/build/plugins/ckan/resource/Resource.d.ts +56 -0
- package/build/plugins/ckan/resource/Resource.js +2 -0
- package/build/plugins/ckan/resource/convert/fromCkan.d.ts +3 -0
- package/build/plugins/ckan/resource/convert/fromCkan.js +39 -0
- package/build/plugins/ckan/resource/convert/toCkan.d.ts +3 -0
- package/build/plugins/ckan/resource/convert/toCkan.js +20 -0
- package/build/plugins/ckan/resource/index.d.ts +3 -0
- package/build/plugins/ckan/resource/index.js +3 -0
- package/build/plugins/ckan/schema/Field.d.ts +34 -0
- package/build/plugins/ckan/schema/Field.js +2 -0
- package/build/plugins/ckan/schema/Schema.d.ts +10 -0
- package/build/plugins/ckan/schema/Schema.js +2 -0
- package/build/plugins/ckan/schema/convert/fixtures/ckan-schema.json +115 -0
- package/build/plugins/ckan/schema/convert/fromCkan.d.ts +3 -0
- package/build/plugins/ckan/schema/convert/fromCkan.js +47 -0
- package/build/plugins/ckan/schema/convert/fromCkan.spec.d.ts +1 -0
- package/build/plugins/ckan/schema/convert/fromCkan.spec.js +157 -0
- package/build/plugins/ckan/schema/convert/toCkan.d.ts +3 -0
- package/build/plugins/ckan/schema/convert/toCkan.js +50 -0
- package/build/plugins/ckan/schema/convert/toCkan.spec.d.ts +1 -0
- package/build/plugins/ckan/schema/convert/toCkan.spec.js +278 -0
- package/build/plugins/ckan/schema/index.d.ts +4 -0
- package/build/plugins/ckan/schema/index.js +3 -0
- package/build/plugins/datahub/index.d.ts +2 -0
- package/build/plugins/datahub/index.js +3 -0
- package/build/plugins/datahub/package/index.d.ts +1 -0
- package/build/plugins/datahub/package/index.js +2 -0
- package/build/plugins/datahub/package/load.d.ts +1 -0
- package/build/plugins/datahub/package/load.js +9 -0
- package/build/plugins/datahub/package/load.spec.d.ts +1 -0
- package/build/plugins/datahub/package/load.spec.js +11 -0
- package/build/plugins/datahub/plugin.d.ts +4 -0
- package/build/plugins/datahub/plugin.js +18 -0
- package/build/plugins/datahub/plugin.spec.d.ts +1 -0
- package/build/plugins/datahub/plugin.spec.js +78 -0
- package/build/plugins/descriptor/index.d.ts +1 -0
- package/build/plugins/descriptor/index.js +2 -0
- package/build/plugins/descriptor/plugin.d.ts +11 -0
- package/build/plugins/descriptor/plugin.js +29 -0
- package/build/plugins/descriptor/plugin.spec.d.ts +1 -0
- package/build/plugins/descriptor/plugin.spec.js +169 -0
- package/build/plugins/folder/index.d.ts +2 -0
- package/build/plugins/folder/index.js +3 -0
- package/build/plugins/folder/package/index.d.ts +2 -0
- package/build/plugins/folder/package/index.js +3 -0
- package/build/plugins/folder/package/load.d.ts +1 -0
- package/build/plugins/folder/package/load.js +6 -0
- package/build/plugins/folder/package/load.spec.d.ts +1 -0
- package/build/plugins/folder/package/load.spec.js +175 -0
- package/build/plugins/folder/package/save.d.ts +7 -0
- package/build/plugins/folder/package/save.js +35 -0
- package/build/plugins/folder/package/save.spec.d.ts +1 -0
- package/build/plugins/folder/package/save.spec.js +328 -0
- package/build/plugins/folder/plugin.d.ts +4 -0
- package/build/plugins/folder/plugin.js +19 -0
- package/build/plugins/folder/plugin.spec.d.ts +1 -0
- package/build/plugins/folder/plugin.spec.js +53 -0
- package/build/plugins/github/github/index.d.ts +1 -0
- package/build/plugins/github/github/index.js +2 -0
- package/build/plugins/github/github/path.d.ts +1 -0
- package/build/plugins/github/github/path.js +4 -0
- package/build/plugins/github/github/request.d.ts +15 -0
- package/build/plugins/github/github/request.js +43 -0
- package/build/plugins/github/index.d.ts +3 -0
- package/build/plugins/github/index.js +4 -0
- package/build/plugins/github/package/License.d.ts +21 -0
- package/build/plugins/github/package/License.js +2 -0
- package/build/plugins/github/package/Owner.d.ts +25 -0
- package/build/plugins/github/package/Owner.js +2 -0
- package/build/plugins/github/package/Package.d.ts +87 -0
- package/build/plugins/github/package/Package.js +2 -0
- package/build/plugins/github/package/convert/fromGithub.d.ts +3 -0
- package/build/plugins/github/package/convert/fromGithub.js +50 -0
- package/build/plugins/github/package/index.d.ts +6 -0
- package/build/plugins/github/package/index.js +4 -0
- package/build/plugins/github/package/load.d.ts +23 -0
- package/build/plugins/github/package/load.js +48 -0
- package/build/plugins/github/package/load.spec.d.ts +1 -0
- package/build/plugins/github/package/load.spec.js +15 -0
- package/build/plugins/github/package/save.d.ts +14 -0
- package/build/plugins/github/package/save.js +69 -0
- package/build/plugins/github/package/save.spec.d.ts +1 -0
- package/build/plugins/github/package/save.spec.js +566 -0
- package/build/plugins/github/plugin.d.ts +19 -0
- package/build/plugins/github/plugin.js +18 -0
- package/build/plugins/github/plugin.spec.d.ts +1 -0
- package/build/plugins/github/plugin.spec.js +73 -0
- package/build/plugins/github/resource/Resource.d.ts +29 -0
- package/build/plugins/github/resource/Resource.js +2 -0
- package/build/plugins/github/resource/convert/fromGithub.d.ts +5 -0
- package/build/plugins/github/resource/convert/fromGithub.js +24 -0
- package/build/plugins/github/resource/convert/toGithub.d.ts +3 -0
- package/build/plugins/github/resource/convert/toGithub.js +10 -0
- package/build/plugins/github/resource/index.d.ts +3 -0
- package/build/plugins/github/resource/index.js +3 -0
- package/build/plugins/zenodo/index.d.ts +3 -0
- package/build/plugins/zenodo/index.js +4 -0
- package/build/plugins/zenodo/package/Creator.d.ts +20 -0
- package/build/plugins/zenodo/package/Creator.js +2 -0
- package/build/plugins/zenodo/package/Package.d.ts +94 -0
- package/build/plugins/zenodo/package/Package.js +2 -0
- package/build/plugins/zenodo/package/convert/fromZenodo.d.ts +3 -0
- package/build/plugins/zenodo/package/convert/fromZenodo.js +43 -0
- package/build/plugins/zenodo/package/convert/toZenodo.d.ts +3 -0
- package/build/plugins/zenodo/package/convert/toZenodo.js +79 -0
- package/build/plugins/zenodo/package/index.d.ts +6 -0
- package/build/plugins/zenodo/package/index.js +5 -0
- package/build/plugins/zenodo/package/load.d.ts +23 -0
- package/build/plugins/zenodo/package/load.js +45 -0
- package/build/plugins/zenodo/package/load.spec.d.ts +1 -0
- package/build/plugins/zenodo/package/load.spec.js +15 -0
- package/build/plugins/zenodo/package/save.d.ts +13 -0
- package/build/plugins/zenodo/package/save.js +74 -0
- package/build/plugins/zenodo/package/save.spec.d.ts +1 -0
- package/build/plugins/zenodo/package/save.spec.js +524 -0
- package/build/plugins/zenodo/plugin.d.ts +19 -0
- package/build/plugins/zenodo/plugin.js +18 -0
- package/build/plugins/zenodo/plugin.spec.d.ts +1 -0
- package/build/plugins/zenodo/plugin.spec.js +78 -0
- package/build/plugins/zenodo/resource/Resource.d.ts +27 -0
- package/build/plugins/zenodo/resource/Resource.js +2 -0
- package/build/plugins/zenodo/resource/convert/fromZenodo.d.ts +10 -0
- package/build/plugins/zenodo/resource/convert/fromZenodo.js +18 -0
- package/build/plugins/zenodo/resource/convert/toZenodo.d.ts +3 -0
- package/build/plugins/zenodo/resource/convert/toZenodo.js +13 -0
- package/build/plugins/zenodo/resource/index.d.ts +3 -0
- package/build/plugins/zenodo/resource/index.js +3 -0
- package/build/plugins/zenodo/zenodo/index.d.ts +1 -0
- package/build/plugins/zenodo/zenodo/index.js +2 -0
- package/build/plugins/zenodo/zenodo/request.d.ts +12 -0
- package/build/plugins/zenodo/zenodo/request.js +36 -0
- package/build/plugins/zip/index.d.ts +2 -0
- package/build/plugins/zip/index.js +3 -0
- package/build/plugins/zip/package/index.d.ts +2 -0
- package/build/plugins/zip/package/index.js +3 -0
- package/build/plugins/zip/package/load.d.ts +1 -0
- package/build/plugins/zip/package/load.js +30 -0
- package/build/plugins/zip/package/load.spec.d.ts +1 -0
- package/build/plugins/zip/package/load.spec.js +173 -0
- package/build/plugins/zip/package/save.d.ts +5 -0
- package/build/plugins/zip/package/save.js +50 -0
- package/build/plugins/zip/package/save.spec.d.ts +1 -0
- package/build/plugins/zip/package/save.spec.js +287 -0
- package/build/plugins/zip/plugin.d.ts +11 -0
- package/build/plugins/zip/plugin.js +24 -0
- package/build/plugins/zip/plugin.spec.d.ts +1 -0
- package/build/plugins/zip/plugin.spec.js +158 -0
- package/build/resource/index.d.ts +1 -0
- package/build/resource/index.js +2 -0
- package/build/resource/save.d.ts +13 -0
- package/build/resource/save.js +53 -0
- package/build/resource/save.spec.d.ts +1 -0
- package/build/resource/save.spec.js +107 -0
- package/build/stream/concat.d.ts +3 -0
- package/build/stream/concat.js +5 -0
- package/build/stream/index.d.ts +3 -0
- package/build/stream/index.js +4 -0
- package/build/stream/load.d.ts +5 -0
- package/build/stream/load.js +46 -0
- package/build/stream/save.d.ts +5 -0
- package/build/stream/save.js +13 -0
- package/package.json +48 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { blob } from "node:stream/consumers";
|
|
2
|
+
import { convertPackageToDescriptor, getFilename, getFormat, stringifyDescriptor, } from "@frictionless-ts/metadata";
|
|
3
|
+
import { getPackageBasepath } from "../../../package/index.js";
|
|
4
|
+
import { saveResourceFiles } from "../../../resource/index.js";
|
|
5
|
+
import { loadFileStream } from "../../../stream/index.js";
|
|
6
|
+
import { makeCkanApiRequest } from "../ckan/index.js";
|
|
7
|
+
import { convertResourceToCkan } from "../resource/index.js";
|
|
8
|
+
import { convertPackageToCkan } from "./convert/toCkan.js";
|
|
9
|
+
export async function savePackageToCkan(dataPackage, options) {
|
|
10
|
+
const { apiKey, ckanUrl, ownerOrg, datasetName } = options;
|
|
11
|
+
const basepath = getPackageBasepath(dataPackage);
|
|
12
|
+
const ckanPackage = convertPackageToCkan(dataPackage);
|
|
13
|
+
const payload = {
|
|
14
|
+
...ckanPackage,
|
|
15
|
+
name: datasetName,
|
|
16
|
+
owner_org: ownerOrg,
|
|
17
|
+
resources: [],
|
|
18
|
+
};
|
|
19
|
+
const result = await makeCkanApiRequest({
|
|
20
|
+
action: "package_create",
|
|
21
|
+
payload,
|
|
22
|
+
ckanUrl: ckanUrl,
|
|
23
|
+
apiKey: apiKey,
|
|
24
|
+
});
|
|
25
|
+
const url = new URL(ckanUrl);
|
|
26
|
+
url.pathname = `/dataset/${result.name}`;
|
|
27
|
+
const resourceDescriptors = [];
|
|
28
|
+
for (const resource of dataPackage.resources) {
|
|
29
|
+
resourceDescriptors.push(await saveResourceFiles(resource, {
|
|
30
|
+
basepath,
|
|
31
|
+
withRemote: true,
|
|
32
|
+
withoutFolders: true,
|
|
33
|
+
saveFile: async (options) => {
|
|
34
|
+
const filename = getFilename(options.normalizedPath);
|
|
35
|
+
const ckanResource = convertResourceToCkan(resource);
|
|
36
|
+
const payload = {
|
|
37
|
+
...ckanResource,
|
|
38
|
+
package_id: datasetName,
|
|
39
|
+
name: options.denormalizedPath,
|
|
40
|
+
format: getFormat(filename)?.toUpperCase(),
|
|
41
|
+
};
|
|
42
|
+
const upload = {
|
|
43
|
+
name: options.denormalizedPath,
|
|
44
|
+
data: await blob(await loadFileStream(options.normalizedPath)),
|
|
45
|
+
};
|
|
46
|
+
const result = await makeCkanApiRequest({
|
|
47
|
+
action: "resource_create",
|
|
48
|
+
payload,
|
|
49
|
+
upload,
|
|
50
|
+
ckanUrl,
|
|
51
|
+
apiKey,
|
|
52
|
+
});
|
|
53
|
+
return result.url;
|
|
54
|
+
},
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
const descriptor = {
|
|
58
|
+
...convertPackageToDescriptor(dataPackage, { basepath }),
|
|
59
|
+
resources: resourceDescriptors,
|
|
60
|
+
};
|
|
61
|
+
for (const denormalizedPath of ["datapackage.json"]) {
|
|
62
|
+
const payload = {
|
|
63
|
+
package_id: datasetName,
|
|
64
|
+
name: denormalizedPath,
|
|
65
|
+
};
|
|
66
|
+
const upload = {
|
|
67
|
+
name: denormalizedPath,
|
|
68
|
+
data: new Blob([stringifyDescriptor(descriptor)]),
|
|
69
|
+
};
|
|
70
|
+
await makeCkanApiRequest({
|
|
71
|
+
action: "resource_create",
|
|
72
|
+
payload,
|
|
73
|
+
upload,
|
|
74
|
+
ckanUrl,
|
|
75
|
+
apiKey,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
path: result.url,
|
|
80
|
+
datasetUrl: url.toString(),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2F2ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3BsdWdpbnMvY2thbi9wYWNrYWdlL3NhdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLHVCQUF1QixDQUFBO0FBRTVDLE9BQU8sRUFDTCwwQkFBMEIsRUFDMUIsV0FBVyxFQUNYLFNBQVMsRUFDVCxtQkFBbUIsR0FDcEIsTUFBTSwyQkFBMkIsQ0FBQTtBQUNsQyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQTtBQUM5RCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQTtBQUM5RCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sMEJBQTBCLENBQUE7QUFDekQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sa0JBQWtCLENBQUE7QUFFckQsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sc0JBQXNCLENBQUE7QUFDNUQsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFFMUQsTUFBTSxDQUFDLEtBQUssVUFBVSxpQkFBaUIsQ0FDckMsV0FBb0IsRUFDcEIsT0FLQztJQUVELE1BQU0sRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxXQUFXLEVBQUUsR0FBRyxPQUFPLENBQUE7SUFFMUQsTUFBTSxRQUFRLEdBQUcsa0JBQWtCLENBQUMsV0FBVyxDQUFDLENBQUE7SUFDaEQsTUFBTSxXQUFXLEdBQUcsb0JBQW9CLENBQUMsV0FBVyxDQUFDLENBQUE7SUFFckQsTUFBTSxPQUFPLEdBQUc7UUFDZCxHQUFHLFdBQVc7UUFDZCxJQUFJLEVBQUUsV0FBVztRQUNqQixTQUFTLEVBQUUsUUFBUTtRQUNuQixTQUFTLEVBQUUsRUFBRTtLQUNkLENBQUE7SUFFRCxNQUFNLE1BQU0sR0FBRyxNQUFNLGtCQUFrQixDQUFDO1FBQ3RDLE1BQU0sRUFBRSxnQkFBZ0I7UUFDeEIsT0FBTztRQUNQLE9BQU8sRUFBRSxPQUFPO1FBQ2hCLE1BQU0sRUFBRSxNQUFNO0tBQ2YsQ0FBQyxDQUFBO0lBRUYsTUFBTSxHQUFHLEdBQUcsSUFBSSxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUE7SUFDNUIsR0FBRyxDQUFDLFFBQVEsR0FBRyxZQUFZLE1BQU0sQ0FBQyxJQUFJLEVBQUUsQ0FBQTtJQUV4QyxNQUFNLG1CQUFtQixHQUFpQixFQUFFLENBQUE7SUFDNUMsS0FBSyxNQUFNLFFBQVEsSUFBSSxXQUFXLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDN0MsbUJBQW1CLENBQUMsSUFBSSxDQUN0QixNQUFNLGlCQUFpQixDQUFDLFFBQVEsRUFBRTtZQUNoQyxRQUFRO1lBQ1IsVUFBVSxFQUFFLElBQUk7WUFDaEIsY0FBYyxFQUFFLElBQUk7WUFDcEIsUUFBUSxFQUFFLEtBQUssRUFBQyxPQUFPLEVBQUMsRUFBRTtnQkFDeEIsTUFBTSxRQUFRLEdBQUcsV0FBVyxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsQ0FBQTtnQkFDcEQsTUFBTSxZQUFZLEdBQUcscUJBQXFCLENBQUMsUUFBUSxDQUFDLENBQUE7Z0JBRXBELE1BQU0sT0FBTyxHQUFHO29CQUNkLEdBQUcsWUFBWTtvQkFDZixVQUFVLEVBQUUsV0FBVztvQkFDdkIsSUFBSSxFQUFFLE9BQU8sQ0FBQyxnQkFBZ0I7b0JBQzlCLE1BQU0sRUFBRSxTQUFTLENBQUMsUUFBUSxDQUFDLEVBQUUsV0FBVyxFQUFFO2lCQUMzQyxDQUFBO2dCQUVELE1BQU0sTUFBTSxHQUFHO29CQUNiLElBQUksRUFBRSxPQUFPLENBQUMsZ0JBQWdCO29CQUM5QixJQUFJLEVBQUUsTUFBTSxJQUFJLENBQUMsTUFBTSxjQUFjLENBQUMsT0FBTyxDQUFDLGNBQWMsQ0FBQyxDQUFDO2lCQUMvRCxDQUFBO2dCQUVELE1BQU0sTUFBTSxHQUFHLE1BQU0sa0JBQWtCLENBQWU7b0JBQ3BELE1BQU0sRUFBRSxpQkFBaUI7b0JBQ3pCLE9BQU87b0JBQ1AsTUFBTTtvQkFDTixPQUFPO29CQUNQLE1BQU07aUJBQ1AsQ0FBQyxDQUFBO2dCQUVGLE9BQU8sTUFBTSxDQUFDLEdBQUcsQ0FBQTtZQUNuQixDQUFDO1NBQ0YsQ0FBQyxDQUNILENBQUE7SUFDSCxDQUFDO0lBRUQsTUFBTSxVQUFVLEdBQUc7UUFDakIsR0FBRywwQkFBMEIsQ0FBQyxXQUFXLEVBQUUsRUFBRSxRQUFRLEVBQUUsQ0FBQztRQUN4RCxTQUFTLEVBQUUsbUJBQW1CO0tBQy9CLENBQUE7SUFFRCxLQUFLLE1BQU0sZ0JBQWdCLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxFQUFFLENBQUM7UUFDcEQsTUFBTSxPQUFPLEdBQUc7WUFDZCxVQUFVLEVBQUUsV0FBVztZQUN2QixJQUFJLEVBQUUsZ0JBQWdCO1NBQ3ZCLENBQUE7UUFFRCxNQUFNLE1BQU0sR0FBRztZQUNiLElBQUksRUFBRSxnQkFBZ0I7WUFDdEIsSUFBSSxFQUFFLElBQUksSUFBSSxDQUFDLENBQUMsbUJBQW1CLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztTQUNsRCxDQUFBO1FBRUQsTUFBTSxrQkFBa0IsQ0FBQztZQUN2QixNQUFNLEVBQUUsaUJBQWlCO1lBQ3pCLE9BQU87WUFDUCxNQUFNO1lBQ04sT0FBTztZQUNQLE1BQU07U0FDUCxDQUFDLENBQUE7SUFDSixDQUFDO0lBRUQsT0FBTztRQUNMLElBQUksRUFBRSxNQUFNLENBQUMsR0FBRztRQUNoQixVQUFVLEVBQUUsR0FBRyxDQUFDLFFBQVEsRUFBRTtLQUMzQixDQUFBO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGJsb2IgfSBmcm9tIFwibm9kZTpzdHJlYW0vY29uc3VtZXJzXCJcbmltcG9ydCB0eXBlIHsgRGVzY3JpcHRvciwgUGFja2FnZSB9IGZyb20gXCJAZnJpY3Rpb25sZXNzLXRzL21ldGFkYXRhXCJcbmltcG9ydCB7XG4gIGNvbnZlcnRQYWNrYWdlVG9EZXNjcmlwdG9yLFxuICBnZXRGaWxlbmFtZSxcbiAgZ2V0Rm9ybWF0LFxuICBzdHJpbmdpZnlEZXNjcmlwdG9yLFxufSBmcm9tIFwiQGZyaWN0aW9ubGVzcy10cy9tZXRhZGF0YVwiXG5pbXBvcnQgeyBnZXRQYWNrYWdlQmFzZXBhdGggfSBmcm9tIFwiLi4vLi4vLi4vcGFja2FnZS9pbmRleC50c1wiXG5pbXBvcnQgeyBzYXZlUmVzb3VyY2VGaWxlcyB9IGZyb20gXCIuLi8uLi8uLi9yZXNvdXJjZS9pbmRleC50c1wiXG5pbXBvcnQgeyBsb2FkRmlsZVN0cmVhbSB9IGZyb20gXCIuLi8uLi8uLi9zdHJlYW0vaW5kZXgudHNcIlxuaW1wb3J0IHsgbWFrZUNrYW5BcGlSZXF1ZXN0IH0gZnJvbSBcIi4uL2NrYW4vaW5kZXgudHNcIlxuaW1wb3J0IHR5cGUgeyBDa2FuUmVzb3VyY2UgfSBmcm9tIFwiLi4vcmVzb3VyY2UvaW5kZXgudHNcIlxuaW1wb3J0IHsgY29udmVydFJlc291cmNlVG9Da2FuIH0gZnJvbSBcIi4uL3Jlc291cmNlL2luZGV4LnRzXCJcbmltcG9ydCB7IGNvbnZlcnRQYWNrYWdlVG9Da2FuIH0gZnJvbSBcIi4vY29udmVydC90b0NrYW4udHNcIlxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2F2ZVBhY2thZ2VUb0NrYW4oXG4gIGRhdGFQYWNrYWdlOiBQYWNrYWdlLFxuICBvcHRpb25zOiB7XG4gICAgYXBpS2V5OiBzdHJpbmdcbiAgICBja2FuVXJsOiBzdHJpbmdcbiAgICBvd25lck9yZzogc3RyaW5nXG4gICAgZGF0YXNldE5hbWU6IHN0cmluZ1xuICB9LFxuKSB7XG4gIGNvbnN0IHsgYXBpS2V5LCBja2FuVXJsLCBvd25lck9yZywgZGF0YXNldE5hbWUgfSA9IG9wdGlvbnNcblxuICBjb25zdCBiYXNlcGF0aCA9IGdldFBhY2thZ2VCYXNlcGF0aChkYXRhUGFja2FnZSlcbiAgY29uc3QgY2thblBhY2thZ2UgPSBjb252ZXJ0UGFja2FnZVRvQ2thbihkYXRhUGFja2FnZSlcblxuICBjb25zdCBwYXlsb2FkID0ge1xuICAgIC4uLmNrYW5QYWNrYWdlLFxuICAgIG5hbWU6IGRhdGFzZXROYW1lLFxuICAgIG93bmVyX29yZzogb3duZXJPcmcsXG4gICAgcmVzb3VyY2VzOiBbXSxcbiAgfVxuXG4gIGNvbnN0IHJlc3VsdCA9IGF3YWl0IG1ha2VDa2FuQXBpUmVxdWVzdCh7XG4gICAgYWN0aW9uOiBcInBhY2thZ2VfY3JlYXRlXCIsXG4gICAgcGF5bG9hZCxcbiAgICBja2FuVXJsOiBja2FuVXJsLFxuICAgIGFwaUtleTogYXBpS2V5LFxuICB9KVxuXG4gIGNvbnN0IHVybCA9IG5ldyBVUkwoY2thblVybClcbiAgdXJsLnBhdGhuYW1lID0gYC9kYXRhc2V0LyR7cmVzdWx0Lm5hbWV9YFxuXG4gIGNvbnN0IHJlc291cmNlRGVzY3JpcHRvcnM6IERlc2NyaXB0b3JbXSA9IFtdXG4gIGZvciAoY29uc3QgcmVzb3VyY2Ugb2YgZGF0YVBhY2thZ2UucmVzb3VyY2VzKSB7XG4gICAgcmVzb3VyY2VEZXNjcmlwdG9ycy5wdXNoKFxuICAgICAgYXdhaXQgc2F2ZVJlc291cmNlRmlsZXMocmVzb3VyY2UsIHtcbiAgICAgICAgYmFzZXBhdGgsXG4gICAgICAgIHdpdGhSZW1vdGU6IHRydWUsXG4gICAgICAgIHdpdGhvdXRGb2xkZXJzOiB0cnVlLFxuICAgICAgICBzYXZlRmlsZTogYXN5bmMgb3B0aW9ucyA9PiB7XG4gICAgICAgICAgY29uc3QgZmlsZW5hbWUgPSBnZXRGaWxlbmFtZShvcHRpb25zLm5vcm1hbGl6ZWRQYXRoKVxuICAgICAgICAgIGNvbnN0IGNrYW5SZXNvdXJjZSA9IGNvbnZlcnRSZXNvdXJjZVRvQ2thbihyZXNvdXJjZSlcblxuICAgICAgICAgIGNvbnN0IHBheWxvYWQgPSB7XG4gICAgICAgICAgICAuLi5ja2FuUmVzb3VyY2UsXG4gICAgICAgICAgICBwYWNrYWdlX2lkOiBkYXRhc2V0TmFtZSxcbiAgICAgICAgICAgIG5hbWU6IG9wdGlvbnMuZGVub3JtYWxpemVkUGF0aCxcbiAgICAgICAgICAgIGZvcm1hdDogZ2V0Rm9ybWF0KGZpbGVuYW1lKT8udG9VcHBlckNhc2UoKSxcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjb25zdCB1cGxvYWQgPSB7XG4gICAgICAgICAgICBuYW1lOiBvcHRpb25zLmRlbm9ybWFsaXplZFBhdGgsXG4gICAgICAgICAgICBkYXRhOiBhd2FpdCBibG9iKGF3YWl0IGxvYWRGaWxlU3RyZWFtKG9wdGlvbnMubm9ybWFsaXplZFBhdGgpKSxcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBtYWtlQ2thbkFwaVJlcXVlc3Q8Q2thblJlc291cmNlPih7XG4gICAgICAgICAgICBhY3Rpb246IFwicmVzb3VyY2VfY3JlYXRlXCIsXG4gICAgICAgICAgICBwYXlsb2FkLFxuICAgICAgICAgICAgdXBsb2FkLFxuICAgICAgICAgICAgY2thblVybCxcbiAgICAgICAgICAgIGFwaUtleSxcbiAgICAgICAgICB9KVxuXG4gICAgICAgICAgcmV0dXJuIHJlc3VsdC51cmxcbiAgICAgICAgfSxcbiAgICAgIH0pLFxuICAgIClcbiAgfVxuXG4gIGNvbnN0IGRlc2NyaXB0b3IgPSB7XG4gICAgLi4uY29udmVydFBhY2thZ2VUb0Rlc2NyaXB0b3IoZGF0YVBhY2thZ2UsIHsgYmFzZXBhdGggfSksXG4gICAgcmVzb3VyY2VzOiByZXNvdXJjZURlc2NyaXB0b3JzLFxuICB9XG5cbiAgZm9yIChjb25zdCBkZW5vcm1hbGl6ZWRQYXRoIG9mIFtcImRhdGFwYWNrYWdlLmpzb25cIl0pIHtcbiAgICBjb25zdCBwYXlsb2FkID0ge1xuICAgICAgcGFja2FnZV9pZDogZGF0YXNldE5hbWUsXG4gICAgICBuYW1lOiBkZW5vcm1hbGl6ZWRQYXRoLFxuICAgIH1cblxuICAgIGNvbnN0IHVwbG9hZCA9IHtcbiAgICAgIG5hbWU6IGRlbm9ybWFsaXplZFBhdGgsXG4gICAgICBkYXRhOiBuZXcgQmxvYihbc3RyaW5naWZ5RGVzY3JpcHRvcihkZXNjcmlwdG9yKV0pLFxuICAgIH1cblxuICAgIGF3YWl0IG1ha2VDa2FuQXBpUmVxdWVzdCh7XG4gICAgICBhY3Rpb246IFwicmVzb3VyY2VfY3JlYXRlXCIsXG4gICAgICBwYXlsb2FkLFxuICAgICAgdXBsb2FkLFxuICAgICAgY2thblVybCxcbiAgICAgIGFwaUtleSxcbiAgICB9KVxuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBwYXRoOiByZXN1bHQudXJsLFxuICAgIGRhdGFzZXRVcmw6IHVybC50b1N0cmluZygpLFxuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { relative } from "node:path";
|
|
2
|
+
import { loadPackageDescriptor } from "@frictionless-ts/metadata";
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
4
|
+
import { savePackageToCkan } from "./save.js";
|
|
5
|
+
describe("savePackageToCkan", () => {
|
|
6
|
+
const getFixturePath = (name) => relative(process.cwd(), `${import.meta.dirname}/fixtures/${name}`);
|
|
7
|
+
const mockPackage = {
|
|
8
|
+
name: "test-package",
|
|
9
|
+
title: "Test Package",
|
|
10
|
+
description: "A test package",
|
|
11
|
+
version: "1.0.0",
|
|
12
|
+
resources: [
|
|
13
|
+
{
|
|
14
|
+
name: "test-resource",
|
|
15
|
+
path: getFixturePath("data.csv"),
|
|
16
|
+
format: "csv",
|
|
17
|
+
bytes: 100,
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
};
|
|
21
|
+
const mockOptions = {
|
|
22
|
+
apiKey: "test-api-key",
|
|
23
|
+
ckanUrl: "https://ckan.example.com",
|
|
24
|
+
ownerOrg: "test-org",
|
|
25
|
+
datasetName: "test-dataset",
|
|
26
|
+
};
|
|
27
|
+
const originalFetch = globalThis.fetch;
|
|
28
|
+
let fetchMock;
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
fetchMock = vi.fn();
|
|
31
|
+
// @ts-ignore
|
|
32
|
+
globalThis.fetch = fetchMock;
|
|
33
|
+
});
|
|
34
|
+
afterEach(() => {
|
|
35
|
+
globalThis.fetch = originalFetch;
|
|
36
|
+
vi.resetAllMocks();
|
|
37
|
+
});
|
|
38
|
+
it.skip("should save a package", async () => {
|
|
39
|
+
const dataPackage = await loadPackageDescriptor("core/package/fixtures/package.json");
|
|
40
|
+
const result = await savePackageToCkan(dataPackage, {
|
|
41
|
+
ckanUrl: "http://localhost:5000/",
|
|
42
|
+
apiKey: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJ1T0Y0VUNybTU5Y0dzdlk3ejhreF9CeC02R0w4RDBOdW9QS0J0WkJFXzlJIiwiaWF0IjoxNzQ3OTI0NDg5fQ.ioGiLlZkm24xHQRBas5X5ig5eU7u_fIjkl4oifGnLaA",
|
|
43
|
+
datasetName: "test",
|
|
44
|
+
ownerOrg: "test",
|
|
45
|
+
});
|
|
46
|
+
expect(result).toBeDefined();
|
|
47
|
+
});
|
|
48
|
+
it("creates a package in CKAN with correct API calls", async () => {
|
|
49
|
+
fetchMock.mockResolvedValueOnce({
|
|
50
|
+
ok: true,
|
|
51
|
+
json: () => Promise.resolve({
|
|
52
|
+
success: true,
|
|
53
|
+
result: {
|
|
54
|
+
name: "test-dataset",
|
|
55
|
+
url: "https://ckan.example.com/dataset/test-dataset",
|
|
56
|
+
},
|
|
57
|
+
}),
|
|
58
|
+
});
|
|
59
|
+
fetchMock.mockResolvedValueOnce({
|
|
60
|
+
ok: true,
|
|
61
|
+
json: () => Promise.resolve({
|
|
62
|
+
success: true,
|
|
63
|
+
result: {
|
|
64
|
+
id: "resource-1",
|
|
65
|
+
url: "https://ckan.example.com/dataset/test-dataset/resource/resource-1",
|
|
66
|
+
},
|
|
67
|
+
}),
|
|
68
|
+
});
|
|
69
|
+
fetchMock.mockResolvedValueOnce({
|
|
70
|
+
ok: true,
|
|
71
|
+
json: () => Promise.resolve({
|
|
72
|
+
success: true,
|
|
73
|
+
result: {
|
|
74
|
+
id: "resource-2",
|
|
75
|
+
url: "https://ckan.example.com/dataset/test-dataset/resource/resource-2",
|
|
76
|
+
},
|
|
77
|
+
}),
|
|
78
|
+
});
|
|
79
|
+
const result = await savePackageToCkan(mockPackage, mockOptions);
|
|
80
|
+
expect(fetchMock).toHaveBeenCalledTimes(3);
|
|
81
|
+
const packageCreateCall = fetchMock.mock.calls[0];
|
|
82
|
+
expect(packageCreateCall).toBeDefined();
|
|
83
|
+
if (!packageCreateCall)
|
|
84
|
+
return;
|
|
85
|
+
expect(packageCreateCall[0]).toEqual("https://ckan.example.com/api/3/action/package_create");
|
|
86
|
+
expect(packageCreateCall[1]).toMatchObject({
|
|
87
|
+
method: "POST",
|
|
88
|
+
headers: {
|
|
89
|
+
Authorization: "test-api-key",
|
|
90
|
+
"Content-Type": "application/json",
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
const packagePayload = JSON.parse(packageCreateCall[1].body);
|
|
94
|
+
expect(packagePayload.name).toEqual("test-dataset");
|
|
95
|
+
expect(packagePayload.owner_org).toEqual("test-org");
|
|
96
|
+
expect(packagePayload.title).toEqual("Test Package");
|
|
97
|
+
expect(packagePayload.notes).toEqual("A test package");
|
|
98
|
+
expect(packagePayload.resources).toEqual([]);
|
|
99
|
+
expect(result).toEqual({
|
|
100
|
+
path: "https://ckan.example.com/dataset/test-dataset",
|
|
101
|
+
datasetUrl: "https://ckan.example.com/dataset/test-dataset",
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
it("creates resources with file uploads", async () => {
|
|
105
|
+
fetchMock.mockResolvedValueOnce({
|
|
106
|
+
ok: true,
|
|
107
|
+
json: () => Promise.resolve({
|
|
108
|
+
success: true,
|
|
109
|
+
result: {
|
|
110
|
+
name: "test-dataset",
|
|
111
|
+
url: "https://ckan.example.com/dataset/test-dataset",
|
|
112
|
+
},
|
|
113
|
+
}),
|
|
114
|
+
});
|
|
115
|
+
fetchMock.mockResolvedValueOnce({
|
|
116
|
+
ok: true,
|
|
117
|
+
json: () => Promise.resolve({
|
|
118
|
+
success: true,
|
|
119
|
+
result: {
|
|
120
|
+
id: "resource-1",
|
|
121
|
+
url: "https://ckan.example.com/dataset/test-dataset/resource/resource-1",
|
|
122
|
+
},
|
|
123
|
+
}),
|
|
124
|
+
});
|
|
125
|
+
fetchMock.mockResolvedValueOnce({
|
|
126
|
+
ok: true,
|
|
127
|
+
json: () => Promise.resolve({
|
|
128
|
+
success: true,
|
|
129
|
+
result: {
|
|
130
|
+
id: "resource-2",
|
|
131
|
+
url: "https://ckan.example.com/dataset/test-dataset/resource/resource-2",
|
|
132
|
+
},
|
|
133
|
+
}),
|
|
134
|
+
});
|
|
135
|
+
await savePackageToCkan(mockPackage, mockOptions);
|
|
136
|
+
const resourceCreateCall = fetchMock.mock.calls[1];
|
|
137
|
+
expect(resourceCreateCall).toBeDefined();
|
|
138
|
+
if (!resourceCreateCall)
|
|
139
|
+
return;
|
|
140
|
+
expect(resourceCreateCall[0]).toEqual("https://ckan.example.com/api/3/action/resource_create");
|
|
141
|
+
expect(resourceCreateCall[1]).toMatchObject({
|
|
142
|
+
method: "POST",
|
|
143
|
+
headers: {
|
|
144
|
+
Authorization: "test-api-key",
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
const formData = resourceCreateCall[1].body;
|
|
148
|
+
expect(formData).toBeInstanceOf(FormData);
|
|
149
|
+
expect(formData.get("package_id")).toEqual("test-dataset");
|
|
150
|
+
expect(formData.get("name")).toEqual("data.csv");
|
|
151
|
+
});
|
|
152
|
+
it("creates datapackage.json resource", async () => {
|
|
153
|
+
fetchMock.mockResolvedValueOnce({
|
|
154
|
+
ok: true,
|
|
155
|
+
json: () => Promise.resolve({
|
|
156
|
+
success: true,
|
|
157
|
+
result: {
|
|
158
|
+
name: "test-dataset",
|
|
159
|
+
url: "https://ckan.example.com/dataset/test-dataset",
|
|
160
|
+
},
|
|
161
|
+
}),
|
|
162
|
+
});
|
|
163
|
+
fetchMock.mockResolvedValueOnce({
|
|
164
|
+
ok: true,
|
|
165
|
+
json: () => Promise.resolve({
|
|
166
|
+
success: true,
|
|
167
|
+
result: {
|
|
168
|
+
id: "resource-1",
|
|
169
|
+
url: "https://ckan.example.com/dataset/test-dataset/resource/resource-1",
|
|
170
|
+
},
|
|
171
|
+
}),
|
|
172
|
+
});
|
|
173
|
+
fetchMock.mockResolvedValueOnce({
|
|
174
|
+
ok: true,
|
|
175
|
+
json: () => Promise.resolve({
|
|
176
|
+
success: true,
|
|
177
|
+
result: {
|
|
178
|
+
id: "resource-2",
|
|
179
|
+
url: "https://ckan.example.com/dataset/test-dataset/resource/resource-2",
|
|
180
|
+
},
|
|
181
|
+
}),
|
|
182
|
+
});
|
|
183
|
+
await savePackageToCkan(mockPackage, mockOptions);
|
|
184
|
+
const datapackageCreateCall = fetchMock.mock.calls[2];
|
|
185
|
+
expect(datapackageCreateCall).toBeDefined();
|
|
186
|
+
if (!datapackageCreateCall)
|
|
187
|
+
return;
|
|
188
|
+
expect(datapackageCreateCall[0]).toEqual("https://ckan.example.com/api/3/action/resource_create");
|
|
189
|
+
const formData = datapackageCreateCall[1].body;
|
|
190
|
+
expect(formData).toBeInstanceOf(FormData);
|
|
191
|
+
expect(formData.get("package_id")).toEqual("test-dataset");
|
|
192
|
+
expect(formData.get("name")).toEqual("datapackage.json");
|
|
193
|
+
const uploadBlob = formData.get("upload");
|
|
194
|
+
expect(uploadBlob).toBeInstanceOf(Blob);
|
|
195
|
+
});
|
|
196
|
+
it("handles API errors from package_create", async () => {
|
|
197
|
+
fetchMock.mockResolvedValueOnce({
|
|
198
|
+
ok: false,
|
|
199
|
+
status: 400,
|
|
200
|
+
statusText: "Bad Request",
|
|
201
|
+
text: () => Promise.resolve("Invalid package data"),
|
|
202
|
+
});
|
|
203
|
+
await expect(savePackageToCkan(mockPackage, mockOptions)).rejects.toThrow("CKAN API error: 400 Bad Request");
|
|
204
|
+
});
|
|
205
|
+
it("handles API errors from resource_create", async () => {
|
|
206
|
+
fetchMock.mockResolvedValueOnce({
|
|
207
|
+
ok: true,
|
|
208
|
+
json: () => Promise.resolve({
|
|
209
|
+
success: true,
|
|
210
|
+
result: {
|
|
211
|
+
name: "test-dataset",
|
|
212
|
+
url: "https://ckan.example.com/dataset/test-dataset",
|
|
213
|
+
},
|
|
214
|
+
}),
|
|
215
|
+
});
|
|
216
|
+
fetchMock.mockResolvedValueOnce({
|
|
217
|
+
ok: false,
|
|
218
|
+
status: 500,
|
|
219
|
+
statusText: "Internal Server Error",
|
|
220
|
+
text: () => Promise.resolve("Failed to create resource"),
|
|
221
|
+
});
|
|
222
|
+
await expect(savePackageToCkan(mockPackage, mockOptions)).rejects.toThrow("CKAN API error: 500 Internal Server Error");
|
|
223
|
+
});
|
|
224
|
+
it("handles CKAN API success: false responses", async () => {
|
|
225
|
+
fetchMock.mockResolvedValueOnce({
|
|
226
|
+
ok: true,
|
|
227
|
+
json: () => Promise.resolve({
|
|
228
|
+
success: false,
|
|
229
|
+
error: {
|
|
230
|
+
message: "Package already exists",
|
|
231
|
+
},
|
|
232
|
+
}),
|
|
233
|
+
});
|
|
234
|
+
await expect(savePackageToCkan(mockPackage, mockOptions)).rejects.toThrow("CKAN API error");
|
|
235
|
+
});
|
|
236
|
+
it("handles packages with multiple resources", async () => {
|
|
237
|
+
const multiResourcePackage = {
|
|
238
|
+
...mockPackage,
|
|
239
|
+
resources: [
|
|
240
|
+
{
|
|
241
|
+
name: "resource-1",
|
|
242
|
+
path: getFixturePath("data.csv"),
|
|
243
|
+
format: "csv",
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
name: "resource-2",
|
|
247
|
+
path: getFixturePath("data.csv"),
|
|
248
|
+
format: "json",
|
|
249
|
+
},
|
|
250
|
+
],
|
|
251
|
+
};
|
|
252
|
+
fetchMock.mockResolvedValue({
|
|
253
|
+
ok: true,
|
|
254
|
+
json: () => Promise.resolve({
|
|
255
|
+
success: true,
|
|
256
|
+
result: {
|
|
257
|
+
name: "test-dataset",
|
|
258
|
+
url: "https://ckan.example.com/dataset/test-dataset",
|
|
259
|
+
},
|
|
260
|
+
}),
|
|
261
|
+
});
|
|
262
|
+
await savePackageToCkan(multiResourcePackage, mockOptions);
|
|
263
|
+
expect(fetchMock).toHaveBeenCalledTimes(4);
|
|
264
|
+
const secondResourceCall = fetchMock.mock.calls[2];
|
|
265
|
+
expect(secondResourceCall).toBeDefined();
|
|
266
|
+
if (!secondResourceCall)
|
|
267
|
+
return;
|
|
268
|
+
expect(secondResourceCall[0]).toEqual("https://ckan.example.com/api/3/action/resource_create");
|
|
269
|
+
});
|
|
270
|
+
it("handles packages with no resources", async () => {
|
|
271
|
+
const emptyPackage = {
|
|
272
|
+
...mockPackage,
|
|
273
|
+
resources: [],
|
|
274
|
+
};
|
|
275
|
+
fetchMock.mockResolvedValueOnce({
|
|
276
|
+
ok: true,
|
|
277
|
+
json: () => Promise.resolve({
|
|
278
|
+
success: true,
|
|
279
|
+
result: {
|
|
280
|
+
name: "test-dataset",
|
|
281
|
+
url: "https://ckan.example.com/dataset/test-dataset",
|
|
282
|
+
},
|
|
283
|
+
}),
|
|
284
|
+
});
|
|
285
|
+
fetchMock.mockResolvedValueOnce({
|
|
286
|
+
ok: true,
|
|
287
|
+
json: () => Promise.resolve({
|
|
288
|
+
success: true,
|
|
289
|
+
result: {
|
|
290
|
+
id: "resource-1",
|
|
291
|
+
url: "https://ckan.example.com/dataset/test-dataset/resource/resource-1",
|
|
292
|
+
},
|
|
293
|
+
}),
|
|
294
|
+
});
|
|
295
|
+
const result = await savePackageToCkan(emptyPackage, mockOptions);
|
|
296
|
+
expect(fetchMock).toHaveBeenCalledTimes(2);
|
|
297
|
+
expect(result.datasetUrl).toEqual("https://ckan.example.com/dataset/test-dataset");
|
|
298
|
+
});
|
|
299
|
+
it("passes API key in Authorization header", async () => {
|
|
300
|
+
fetchMock.mockResolvedValue({
|
|
301
|
+
ok: true,
|
|
302
|
+
json: () => Promise.resolve({
|
|
303
|
+
success: true,
|
|
304
|
+
result: { name: "test-dataset" },
|
|
305
|
+
}),
|
|
306
|
+
});
|
|
307
|
+
await savePackageToCkan(mockPackage, {
|
|
308
|
+
...mockOptions,
|
|
309
|
+
apiKey: "custom-api-key",
|
|
310
|
+
});
|
|
311
|
+
const firstCall = fetchMock.mock.calls[0];
|
|
312
|
+
expect(firstCall).toBeDefined();
|
|
313
|
+
if (!firstCall)
|
|
314
|
+
return;
|
|
315
|
+
const headers = firstCall[1].headers;
|
|
316
|
+
expect(headers.Authorization).toEqual("custom-api-key");
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2F2ZS5zcGVjLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcGx1Z2lucy9ja2FuL3BhY2thZ2Uvc2F2ZS5zcGVjLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxXQUFXLENBQUE7QUFFcEMsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sMkJBQTJCLENBQUE7QUFDakUsT0FBTyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLE1BQU0sUUFBUSxDQUFBO0FBQ3hFLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLFdBQVcsQ0FBQTtBQUU3QyxRQUFRLENBQUMsbUJBQW1CLEVBQUUsR0FBRyxFQUFFO0lBQ2pDLE1BQU0sY0FBYyxHQUFHLENBQUMsSUFBWSxFQUFFLEVBQUUsQ0FDdEMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxhQUFhLElBQUksRUFBRSxDQUFDLENBQUE7SUFFcEUsTUFBTSxXQUFXLEdBQVk7UUFDM0IsSUFBSSxFQUFFLGNBQWM7UUFDcEIsS0FBSyxFQUFFLGNBQWM7UUFDckIsV0FBVyxFQUFFLGdCQUFnQjtRQUM3QixPQUFPLEVBQUUsT0FBTztRQUNoQixTQUFTLEVBQUU7WUFDVDtnQkFDRSxJQUFJLEVBQUUsZUFBZTtnQkFDckIsSUFBSSxFQUFFLGNBQWMsQ0FBQyxVQUFVLENBQUM7Z0JBQ2hDLE1BQU0sRUFBRSxLQUFLO2dCQUNiLEtBQUssRUFBRSxHQUFHO2FBQ1g7U0FDRjtLQUNGLENBQUE7SUFFRCxNQUFNLFdBQVcsR0FBRztRQUNsQixNQUFNLEVBQUUsY0FBYztRQUN0QixPQUFPLEVBQUUsMEJBQTBCO1FBQ25DLFFBQVEsRUFBRSxVQUFVO1FBQ3BCLFdBQVcsRUFBRSxjQUFjO0tBQzVCLENBQUE7SUFFRCxN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QUFFLEVBQUUsSUFBSSxFQUFFLGNBQWMsRUFBRTthQUNqQyxDQUFDO1NBQ0wsQ0FBQyxDQUFBO1FBRUYsTUFBTSxpQkFBaUIsQ0FBQyxXQUFXLEVBQUU7WUFDbkMsR0FBRyxXQUFXO1lBQ2QsTUFBTSxFQUFFLGdCQUFnQjtTQUN6QixDQUFDLENBQUE7UUFFRixNQUFNLFNBQVMsR0FBRyxTQUFTLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQTtRQUN6QyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUMsV0FBVyxFQUFFLENBQUE7UUFDL0IsSUFBSSxDQUFDLFNBQVM7WUFBRSxPQUFNO1FBRXRCLE1BQU0sT0FBTyxHQUFHLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUE7UUFDcEMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsQ0FBQTtJQUN6RCxDQUFDLENBQUMsQ0FBQTtBQUNKLENBQUMsQ0FBQyxDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgcmVsYXRpdmUgfSBmcm9tIFwibm9kZTpwYXRoXCJcbmltcG9ydCB0eXBlIHsgUGFja2FnZSB9IGZyb20gXCJAZnJpY3Rpb25sZXNzLXRzL21ldGFkYXRhXCJcbmltcG9ydCB7IGxvYWRQYWNrYWdlRGVzY3JpcHRvciB9IGZyb20gXCJAZnJpY3Rpb25sZXNzLXRzL21ldGFkYXRhXCJcbmltcG9ydCB7IGFmdGVyRWFjaCwgYmVmb3JlRWFjaCwgZGVzY3JpYmUsIGV4cGVjdCwgaXQsIHZpIH0gZnJvbSBcInZpdGVzdFwiXG5pbXBvcnQgeyBzYXZlUGFja2FnZVRvQ2thbiB9IGZyb20gXCIuL3NhdmUudHNcIlxuXG5kZXNjcmliZShcInNhdmVQYWNrYWdlVG9Da2FuXCIsICgpID0+IHtcbiAgY29uc3QgZ2V0Rml4dHVyZVBhdGggPSAobmFtZTogc3RyaW5nKSA9PlxuICAgIHJlbGF0aXZlKHByb2Nlc3MuY3dkKCksIGAke2ltcG9ydC5tZXRhLmRpcm5hbWV9L2ZpeHR1cmVzLyR7bmFtZX1gKVxuXG4gIGNvbnN0IG1vY2tQYWNrYWdlOiBQYWNrYWdlID0ge1xuICAgIG5hbWU6IFwidGVzdC1wYWNrYWdlXCIsXG4gICAgdGl0bGU6IFwiVGVzdCBQYWNrYWdlXCIsXG4gICAgZGVzY3JpcHRpb246IFwiQSB0ZXN0IHBhY2thZ2VcIixcbiAgICB2ZXJzaW9uOiBcIjEuMC4wXCIsXG4gICAgcmVzb3VyY2VzOiBbXG4gICAgICB7XG4gICAgICAgIG5hbWU6IFwidGVzdC1yZXNvdXJjZVwiLFxuICAgICAgICBwYXRoOiBnZXRGaXh0dXJlUGF0aChcImRhdGEuY3N2XCIpLFxuICAgICAgICBmb3JtYXQ6IFwiY3N2XCIsXG4gICAgICAgIGJ5dGVzOiAxMDAsXG4gICAgICB9LFxuICAgIF0sXG4gIH1cblxuICBjb25zdCBtb2NrT3B0aW9ucyA9IHtcbiAgICBhcGlLZXk6IFwidGVzdC1hcGkta2V5XCIsXG4gICAgY2thblVybDogXCJodHRwczovL2NrYW4uZXhhbXBsZS5jb21cIixcbiAgICBvd25lck9yZzogXCJ0ZXN0LW9yZ1wiLFxuICAgIGRhdGFzZXROYW1lOiBcInRlc3QtZGF0YXNldFwiLFxuICB9XG5cbiAgY29uc3Qgb3JpZ2luYWxGZXRjaCA9IGdsb2JhbFRoaXMuZmV0Y2hcbiAgbGV0IGZldGNoTW9jazogUmV0dXJuVHlwZTx0eXBlb2YgdmkuZm4+XG5cbiAgYmVmb3JlRWFjaCgoKSA9PiB7XG4gICAgZmV0Y2hNb2NrID0gdmkuZm4oKVxuICAgIC8vIEB0cy1pZ25vcmVcbiAgICBnbG9iYWxUaGlzLmZldGNoID0gZmV0Y2hNb2NrXG4gIH0pXG5cbiAgYWZ0ZXJFYWNoKCgpID0+IHtcbiAgICBnbG9iYWxUaGlzLmZldGNoID0gb3JpZ2luYWxGZXRjaFxuICAgIHZpLnJlc2V0QWxsTW9ja3MoKVxuICB9KVxuXG4gIGl0LnNraXAoXCJzaG91bGQgc2F2ZSBhIHBhY2thZ2VcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGRhdGFQYWNrYWdlID0gYXdhaXQgbG9hZFBhY2thZ2VEZXNjcmlwdG9yKFxuICAgICAgXCJjb3JlL3BhY2thZ2UvZml4dHVyZXMvcGFja2FnZS5qc29uXCIsXG4gICAgKVxuXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgc2F2ZVBhY2thZ2VUb0NrYW4oZGF0YVBhY2thZ2UsIHtcbiAgICAgIGNrYW5Vcmw6IFwiaHR0cDovL2xvY2FsaG9zdDo1MDAwL1wiLFxuICAgICAgYXBpS2V5OlxuICAgICAgICBcImV5SmhiR2NpT2lKSVV6STFOaUlzSW5SNWNDSTZJa3BYVkNKOS5leUpxZEdraU9pSjFUMFkwVlVOeWJUVTVZMGR6ZGxrM2VqaHJlRjlDZUMwMlIwdzRSREJPZFc5UVMwSjBXa0pGWHpsSklpd2lhV0YwSWpveE56UTNPVEkwTkRnNWZRLmlvR2lMbFprbTI0eEhRUkJhczVYNWlnNWVVN3VfZklqa2w0b2lmR25MYUFcIixcbiAgICAgIGRhdGFzZXROYW1lOiBcInRlc3RcIixcbiAgICAgIG93bmVyT3JnOiBcInRlc3RcIixcbiAgICB9KVxuXG4gICAgZXhwZWN0KHJlc3VsdCkudG9CZURlZmluZWQoKVxuICB9KVxuXG4gIGl0KFwiY3JlYXRlcyBhIHBhY2thZ2UgaW4gQ0tBTiB3aXRoIGNvcnJlY3QgQVBJIGNhbGxzXCIsIGFzeW5jICgpID0+IHtcbiAgICBmZXRjaE1vY2subW9ja1Jlc29sdmVkVmFsdWVPbmNlKHtcbiAgICAgIG9rOiB0cnVlLFxuICAgICAganNvbjogKCkgPT5cbiAgICAgICAgUHJvbWlzZS5yZXNvbHZlKHtcbiAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgIHJlc3VsdDoge1xuICAgICAgICAgICAgbmFtZTogXCJ0ZXN0LWRhdGFzZXRcIixcbiAgICAgICAgICAgIHVybDogXCJodHRwczovL2NrYW4uZXhhbXBsZS5jb20vZGF0YXNldC90ZXN0LWRhdGFzZXRcIixcbiAgICAgICAgICB9LFxuICAgICAgICB9KSxcbiAgICB9KVxuXG4gICAgZmV0Y2hNb2NrLm1vY2tSZXNvbHZlZFZhbHVlT25jZSh7XG4gICAgICBvazogdHJ1ZSxcbiAgICAgIGpzb246ICgpID0+XG4gICAgICAgIFByb21pc2UucmVzb2x2ZSh7XG4gICAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgICByZXN1bHQ6IHtcbiAgICAgICAgICAgIGlkOiBcInJlc291cmNlLTFcIixcbiAgICAgICAgICAgIHVybDogXCJodHRwczovL2NrYW4uZXhhbXBsZS5jb20vZGF0YXNldC90ZXN0LWRhdGFzZXQvcmVzb3VyY2UvcmVzb3VyY2UtMVwiLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pLFxuICAgIH0pXG5cbiAgICBmZXRjaE1vY2subW9ja1Jlc29sdmVkVmFsdWVPbmNlKHtcbiAgICAgIG9rOiB0cnVlLFxuICAgICAganNvbjogKCkgPT5cbiAgICAgICAgUHJvbWlzZS5yZXNvbHZlKHtcbiAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgIHJlc3VsdDoge1xuICAgICAgICAgICAgaWQ6IFwicmVzb3VyY2UtMlwiLFxuICAgICAgICAgICAgdXJsOiBcImh0dHBzOi8vY2thbi5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldC9yZXNvdXJjZS9yZXNvdXJjZS0yXCIsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSksXG4gICAgfSlcblxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHNhdmVQYWNrYWdlVG9Da2FuKG1vY2tQYWNrYWdlLCBtb2NrT3B0aW9ucylcblxuICAgIGV4cGVjdChmZXRjaE1vY2spLnRvSGF2ZUJlZW5DYWxsZWRUaW1lcygzKVxuXG4gICAgY29uc3QgcGFja2FnZUNyZWF0ZUNhbGwgPSBmZXRjaE1vY2subW9jay5jYWxsc1swXVxuICAgIGV4cGVjdChwYWNrYWdlQ3JlYXRlQ2FsbCkudG9CZURlZmluZWQoKVxuICAgIGlmICghcGFja2FnZUNyZWF0ZUNhbGwpIHJldHVyblxuXG4gICAgZXhwZWN0KHBhY2thZ2VDcmVhdGVDYWxsWzBdKS50b0VxdWFsKFxuICAgICAgXCJodHRwczovL2NrYW4uZXhhbXBsZS5jb20vYXBpLzMvYWN0aW9uL3BhY2thZ2VfY3JlYXRlXCIsXG4gICAgKVxuICAgIGV4cGVjdChwYWNrYWdlQ3JlYXRlQ2FsbFsxXSkudG9NYXRjaE9iamVjdCh7XG4gICAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICBBdXRob3JpemF0aW9uOiBcInRlc3QtYXBpLWtleVwiLFxuICAgICAgICBcIkNvbnRlbnQtVHlwZVwiOiBcImFwcGxpY2F0aW9uL2pzb25cIixcbiAgICAgIH0sXG4gICAgfSlcblxuICAgIGNvbnN0IHBhY2thZ2VQYXlsb2FkID0gSlNPTi5wYXJzZShwYWNrYWdlQ3JlYXRlQ2FsbFsxXS5ib2R5KVxuICAgIGV4cGVjdChwYWNrYWdlUGF5bG9hZC5uYW1lKS50b0VxdWFsKFwidGVzdC1kYXRhc2V0XCIpXG4gICAgZXhwZWN0KHBhY2thZ2VQYXlsb2FkLm93bmVyX29yZykudG9FcXVhbChcInRlc3Qtb3JnXCIpXG4gICAgZXhwZWN0KHBhY2thZ2VQYXlsb2FkLnRpdGxlKS50b0VxdWFsKFwiVGVzdCBQYWNrYWdlXCIpXG4gICAgZXhwZWN0KHBhY2thZ2VQYXlsb2FkLm5vdGVzKS50b0VxdWFsKFwiQSB0ZXN0IHBhY2thZ2VcIilcbiAgICBleHBlY3QocGFja2FnZVBheWxvYWQucmVzb3VyY2VzKS50b0VxdWFsKFtdKVxuXG4gICAgZXhwZWN0KHJlc3VsdCkudG9FcXVhbCh7XG4gICAgICBwYXRoOiBcImh0dHBzOi8vY2thbi5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldFwiLFxuICAgICAgZGF0YXNldFVybDogXCJodHRwczovL2NrYW4uZXhhbXBsZS5jb20vZGF0YXNldC90ZXN0LWRhdGFzZXRcIixcbiAgICB9KVxuICB9KVxuXG4gIGl0KFwiY3JlYXRlcyByZXNvdXJjZXMgd2l0aCBmaWxlIHVwbG9hZHNcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGZldGNoTW9jay5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2Uoe1xuICAgICAgb2s6IHRydWUsXG4gICAgICBqc29uOiAoKSA9PlxuICAgICAgICBQcm9taXNlLnJlc29sdmUoe1xuICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgcmVzdWx0OiB7XG4gICAgICAgICAgICBuYW1lOiBcInRlc3QtZGF0YXNldFwiLFxuICAgICAgICAgICAgdXJsOiBcImh0dHBzOi8vY2thbi5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldFwiLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pLFxuICAgIH0pXG5cbiAgICBmZXRjaE1vY2subW9ja1Jlc29sdmVkVmFsdWVPbmNlKHtcbiAgICAgIG9rOiB0cnVlLFxuICAgICAganNvbjogKCkgPT5cbiAgICAgICAgUHJvbWlzZS5yZXNvbHZlKHtcbiAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgIHJlc3VsdDoge1xuICAgICAgICAgICAgaWQ6IFwicmVzb3VyY2UtMVwiLFxuICAgICAgICAgICAgdXJsOiBcImh0dHBzOi8vY2thbi5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldC9yZXNvdXJjZS9yZXNvdXJjZS0xXCIsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSksXG4gICAgfSlcblxuICAgIGZldGNoTW9jay5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2Uoe1xuICAgICAgb2s6IHRydWUsXG4gICAgICBqc29uOiAoKSA9PlxuICAgICAgICBQcm9taXNlLnJlc29sdmUoe1xuICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgcmVzdWx0OiB7XG4gICAgICAgICAgICBpZDogXCJyZXNvdXJjZS0yXCIsXG4gICAgICAgICAgICB1cmw6IFwiaHR0cHM6Ly9ja2FuLmV4YW1wbGUuY29tL2RhdGFzZXQvdGVzdC1kYXRhc2V0L3Jlc291cmNlL3Jlc291cmNlLTJcIixcbiAgICAgICAgICB9LFxuICAgICAgICB9KSxcbiAgICB9KVxuXG4gICAgYXdhaXQgc2F2ZVBhY2thZ2VUb0NrYW4obW9ja1BhY2thZ2UsIG1vY2tPcHRpb25zKVxuXG4gICAgY29uc3QgcmVzb3VyY2VDcmVhdGVDYWxsID0gZmV0Y2hNb2NrLm1vY2suY2FsbHNbMV1cbiAgICBleHBlY3QocmVzb3VyY2VDcmVhdGVDYWxsKS50b0JlRGVmaW5lZCgpXG4gICAgaWYgKCFyZXNvdXJjZUNyZWF0ZUNhbGwpIHJldHVyblxuXG4gICAgZXhwZWN0KHJlc291cmNlQ3JlYXRlQ2FsbFswXSkudG9FcXVhbChcbiAgICAgIFwiaHR0cHM6Ly9ja2FuLmV4YW1wbGUuY29tL2FwaS8zL2FjdGlvbi9yZXNvdXJjZV9jcmVhdGVcIixcbiAgICApXG4gICAgZXhwZWN0KHJlc291cmNlQ3JlYXRlQ2FsbFsxXSkudG9NYXRjaE9iamVjdCh7XG4gICAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICBBdXRob3JpemF0aW9uOiBcInRlc3QtYXBpLWtleVwiLFxuICAgICAgfSxcbiAgICB9KVxuXG4gICAgY29uc3QgZm9ybURhdGEgPSByZXNvdXJjZUNyZWF0ZUNhbGxbMV0uYm9keVxuICAgIGV4cGVjdChmb3JtRGF0YSkudG9CZUluc3RhbmNlT2YoRm9ybURhdGEpXG4gICAgZXhwZWN0KGZvcm1EYXRhLmdldChcInBhY2thZ2VfaWRcIikpLnRvRXF1YWwoXCJ0ZXN0LWRhdGFzZXRcIilcbiAgICBleHBlY3QoZm9ybURhdGEuZ2V0KFwibmFtZVwiKSkudG9FcXVhbChcImRhdGEuY3N2XCIpXG4gIH0pXG5cbiAgaXQoXCJjcmVhdGVzIGRhdGFwYWNrYWdlLmpzb24gcmVzb3VyY2VcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGZldGNoTW9jay5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2Uoe1xuICAgICAgb2s6IHRydWUsXG4gICAgICBqc29uOiAoKSA9PlxuICAgICAgICBQcm9taXNlLnJlc29sdmUoe1xuICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgcmVzdWx0OiB7XG4gICAgICAgICAgICBuYW1lOiBcInRlc3QtZGF0YXNldFwiLFxuICAgICAgICAgICAgdXJsOiBcImh0dHBzOi8vY2thbi5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldFwiLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pLFxuICAgIH0pXG5cbiAgICBmZXRjaE1vY2subW9ja1Jlc29sdmVkVmFsdWVPbmNlKHtcbiAgICAgIG9rOiB0cnVlLFxuICAgICAganNvbjogKCkgPT5cbiAgICAgICAgUHJvbWlzZS5yZXNvbHZlKHtcbiAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgIHJlc3VsdDoge1xuICAgICAgICAgICAgaWQ6IFwicmVzb3VyY2UtMVwiLFxuICAgICAgICAgICAgdXJsOiBcImh0dHBzOi8vY2thbi5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldC9yZXNvdXJjZS9yZXNvdXJjZS0xXCIsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSksXG4gICAgfSlcblxuICAgIGZldGNoTW9jay5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2Uoe1xuICAgICAgb2s6IHRydWUsXG4gICAgICBqc29uOiAoKSA9PlxuICAgICAgICBQcm9taXNlLnJlc29sdmUoe1xuICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgcmVzdWx0OiB7XG4gICAgICAgICAgICBpZDogXCJyZXNvdXJjZS0yXCIsXG4gICAgICAgICAgICB1cmw6IFwiaHR0cHM6Ly9ja2FuLmV4YW1wbGUuY29tL2RhdGFzZXQvdGVzdC1kYXRhc2V0L3Jlc291cmNlL3Jlc291cmNlLTJcIixcbiAgICAgICAgICB9LFxuICAgICAgICB9KSxcbiAgICB9KVxuXG4gICAgYXdhaXQgc2F2ZVBhY2thZ2VUb0NrYW4obW9ja1BhY2thZ2UsIG1vY2tPcHRpb25zKVxuXG4gICAgY29uc3QgZGF0YXBhY2thZ2VDcmVhdGVDYWxsID0gZmV0Y2hNb2NrLm1vY2suY2FsbHNbMl1cbiAgICBleHBlY3QoZGF0YXBhY2thZ2VDcmVhdGVDYWxsKS50b0JlRGVmaW5lZCgpXG4gICAgaWYgKCFkYXRhcGFja2FnZUNyZWF0ZUNhbGwpIHJldHVyblxuXG4gICAgZXhwZWN0KGRhdGFwYWNrYWdlQ3JlYXRlQ2FsbFswXSkudG9FcXVhbChcbiAgICAgIFwiaHR0cHM6Ly9ja2FuLmV4YW1wbGUuY29tL2FwaS8zL2FjdGlvbi9yZXNvdXJjZV9jcmVhdGVcIixcbiAgICApXG5cbiAgICBjb25zdCBmb3JtRGF0YSA9IGRhdGFwYWNrYWdlQ3JlYXRlQ2FsbFsxXS5ib2R5XG4gICAgZXhwZWN0KGZvcm1EYXRhKS50b0JlSW5zdGFuY2VPZihGb3JtRGF0YSlcbiAgICBleHBlY3QoZm9ybURhdGEuZ2V0KFwicGFja2FnZV9pZFwiKSkudG9FcXVhbChcInRlc3QtZGF0YXNldFwiKVxuICAgIGV4cGVjdChmb3JtRGF0YS5nZXQoXCJuYW1lXCIpKS50b0VxdWFsKFwiZGF0YXBhY2thZ2UuanNvblwiKVxuXG4gICAgY29uc3QgdXBsb2FkQmxvYiA9IGZvcm1EYXRhLmdldChcInVwbG9hZFwiKVxuICAgIGV4cGVjdCh1cGxvYWRCbG9iKS50b0JlSW5zdGFuY2VPZihCbG9iKVxuICB9KVxuXG4gIGl0KFwiaGFuZGxlcyBBUEkgZXJyb3JzIGZyb20gcGFja2FnZV9jcmVhdGVcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGZldGNoTW9jay5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2Uoe1xuICAgICAgb2s6IGZhbHNlLFxuICAgICAgc3RhdHVzOiA0MDAsXG4gICAgICBzdGF0dXNUZXh0OiBcIkJhZCBSZXF1ZXN0XCIsXG4gICAgICB0ZXh0OiAoKSA9PiBQcm9taXNlLnJlc29sdmUoXCJJbnZhbGlkIHBhY2thZ2UgZGF0YVwiKSxcbiAgICB9KVxuXG4gICAgYXdhaXQgZXhwZWN0KHNhdmVQYWNrYWdlVG9Da2FuKG1vY2tQYWNrYWdlLCBtb2NrT3B0aW9ucykpLnJlamVjdHMudG9UaHJvdyhcbiAgICAgIFwiQ0tBTiBBUEkgZXJyb3I6IDQwMCBCYWQgUmVxdWVzdFwiLFxuICAgIClcbiAgfSlcblxuICBpdChcImhhbmRsZXMgQVBJIGVycm9ycyBmcm9tIHJlc291cmNlX2NyZWF0ZVwiLCBhc3luYyAoKSA9PiB7XG4gICAgZmV0Y2hNb2NrLm1vY2tSZXNvbHZlZFZhbHVlT25jZSh7XG4gICAgICBvazogdHJ1ZSxcbiAgICAgIGpzb246ICgpID0+XG4gICAgICAgIFByb21pc2UucmVzb2x2ZSh7XG4gICAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgICByZXN1bHQ6IHtcbiAgICAgICAgICAgIG5hbWU6IFwidGVzdC1kYXRhc2V0XCIsXG4gICAgICAgICAgICB1cmw6IFwiaHR0cHM6Ly9ja2FuLmV4YW1wbGUuY29tL2RhdGFzZXQvdGVzdC1kYXRhc2V0XCIsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSksXG4gICAgfSlcblxuICAgIGZldGNoTW9jay5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2Uoe1xuICAgICAgb2s6IGZhbHNlLFxuICAgICAgc3RhdHVzOiA1MDAsXG4gICAgICBzdGF0dXNUZXh0OiBcIkludGVybmFsIFNlcnZlciBFcnJvclwiLFxuICAgICAgdGV4dDogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKFwiRmFpbGVkIHRvIGNyZWF0ZSByZXNvdXJjZVwiKSxcbiAgICB9KVxuXG4gICAgYXdhaXQgZXhwZWN0KHNhdmVQYWNrYWdlVG9Da2FuKG1vY2tQYWNrYWdlLCBtb2NrT3B0aW9ucykpLnJlamVjdHMudG9UaHJvdyhcbiAgICAgIFwiQ0tBTiBBUEkgZXJyb3I6IDUwMCBJbnRlcm5hbCBTZXJ2ZXIgRXJyb3JcIixcbiAgICApXG4gIH0pXG5cbiAgaXQoXCJoYW5kbGVzIENLQU4gQVBJIHN1Y2Nlc3M6IGZhbHNlIHJlc3BvbnNlc1wiLCBhc3luYyAoKSA9PiB7XG4gICAgZmV0Y2hNb2NrLm1vY2tSZXNvbHZlZFZhbHVlT25jZSh7XG4gICAgICBvazogdHJ1ZSxcbiAgICAgIGpzb246ICgpID0+XG4gICAgICAgIFByb21pc2UucmVzb2x2ZSh7XG4gICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgZXJyb3I6IHtcbiAgICAgICAgICAgIG1lc3NhZ2U6IFwiUGFja2FnZSBhbHJlYWR5IGV4aXN0c1wiLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pLFxuICAgIH0pXG5cbiAgICBhd2FpdCBleHBlY3Qoc2F2ZVBhY2thZ2VUb0NrYW4obW9ja1BhY2thZ2UsIG1vY2tPcHRpb25zKSkucmVqZWN0cy50b1Rocm93KFxuICAgICAgXCJDS0FOIEFQSSBlcnJvclwiLFxuICAgIClcbiAgfSlcblxuICBpdChcImhhbmRsZXMgcGFja2FnZXMgd2l0aCBtdWx0aXBsZSByZXNvdXJjZXNcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IG11bHRpUmVzb3VyY2VQYWNrYWdlOiBQYWNrYWdlID0ge1xuICAgICAgLi4ubW9ja1BhY2thZ2UsXG4gICAgICByZXNvdXJjZXM6IFtcbiAgICAgICAge1xuICAgICAgICAgIG5hbWU6IFwicmVzb3VyY2UtMVwiLFxuICAgICAgICAgIHBhdGg6IGdldEZpeHR1cmVQYXRoKFwiZGF0YS5jc3ZcIiksXG4gICAgICAgICAgZm9ybWF0OiBcImNzdlwiLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgbmFtZTogXCJyZXNvdXJjZS0yXCIsXG4gICAgICAgICAgcGF0aDogZ2V0Rml4dHVyZVBhdGgoXCJkYXRhLmNzdlwiKSxcbiAgICAgICAgICBmb3JtYXQ6IFwianNvblwiLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9XG5cbiAgICBmZXRjaE1vY2subW9ja1Jlc29sdmVkVmFsdWUoe1xuICAgICAgb2s6IHRydWUsXG4gICAgICBqc29uOiAoKSA9PlxuICAgICAgICBQcm9taXNlLnJlc29sdmUoe1xuICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgcmVzdWx0OiB7XG4gICAgICAgICAgICBuYW1lOiBcInRlc3QtZGF0YXNldFwiLFxuICAgICAgICAgICAgdXJsOiBcImh0dHBzOi8vY2thbi5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldFwiLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pLFxuICAgIH0pXG5cbiAgICBhd2FpdCBzYXZlUGFja2FnZVRvQ2thbihtdWx0aVJlc291cmNlUGFja2FnZSwgbW9ja09wdGlvbnMpXG5cbiAgICBleHBlY3QoZmV0Y2hNb2NrKS50b0hhdmVCZWVuQ2FsbGVkVGltZXMoNClcblxuICAgIGNvbnN0IHNlY29uZFJlc291cmNlQ2FsbCA9IGZldGNoTW9jay5tb2NrLmNhbGxzWzJdXG4gICAgZXhwZWN0KHNlY29uZFJlc291cmNlQ2FsbCkudG9CZURlZmluZWQoKVxuICAgIGlmICghc2Vjb25kUmVzb3VyY2VDYWxsKSByZXR1cm5cblxuICAgIGV4cGVjdChzZWNvbmRSZXNvdXJjZUNhbGxbMF0pLnRvRXF1YWwoXG4gICAgICBcImh0dHBzOi8vY2thbi5leGFtcGxlLmNvbS9hcGkvMy9hY3Rpb24vcmVzb3VyY2VfY3JlYXRlXCIsXG4gICAgKVxuICB9KVxuXG4gIGl0KFwiaGFuZGxlcyBwYWNrYWdlcyB3aXRoIG5vIHJlc291cmNlc1wiLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgZW1wdHlQYWNrYWdlOiBQYWNrYWdlID0ge1xuICAgICAgLi4ubW9ja1BhY2thZ2UsXG4gICAgICByZXNvdXJjZXM6IFtdLFxuICAgIH1cblxuICAgIGZldGNoTW9jay5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2Uoe1xuICAgICAgb2s6IHRydWUsXG4gICAgICBqc29uOiAoKSA9PlxuICAgICAgICBQcm9taXNlLnJlc29sdmUoe1xuICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgcmVzdWx0OiB7XG4gICAgICAgICAgICBuYW1lOiBcInRlc3QtZGF0YXNldFwiLFxuICAgICAgICAgICAgdXJsOiBcImh0dHBzOi8vY2thbi5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldFwiLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pLFxuICAgIH0pXG5cbiAgICBmZXRjaE1vY2subW9ja1Jlc29sdmVkVmFsdWVPbmNlKHtcbiAgICAgIG9rOiB0cnVlLFxuICAgICAganNvbjogKCkgPT5cbiAgICAgICAgUHJvbWlzZS5yZXNvbHZlKHtcbiAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgIHJlc3VsdDoge1xuICAgICAgICAgICAgaWQ6IFwicmVzb3VyY2UtMVwiLFxuICAgICAgICAgICAgdXJsOiBcImh0dHBzOi8vY2thbi5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldC9yZXNvdXJjZS9yZXNvdXJjZS0xXCIsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSksXG4gICAgfSlcblxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHNhdmVQYWNrYWdlVG9Da2FuKGVtcHR5UGFja2FnZSwgbW9ja09wdGlvbnMpXG5cbiAgICBleHBlY3QoZmV0Y2hNb2NrKS50b0hhdmVCZWVuQ2FsbGVkVGltZXMoMilcbiAgICBleHBlY3QocmVzdWx0LmRhdGFzZXRVcmwpLnRvRXF1YWwoXG4gICAgICBcImh0dHBzOi8vY2thbi5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldFwiLFxuICAgIClcbiAgfSlcblxuICBpdChcInBhc3NlcyBBUEkga2V5IGluIEF1dGhvcml6YXRpb24gaGVhZGVyXCIsIGFzeW5jICgpID0+IHtcbiAgICBmZXRjaE1vY2subW9ja1Jlc29sdmVkVmFsdWUoe1xuICAgICAgb2s6IHRydWUsXG4gICAgICBqc29uOiAoKSA9PlxuICAgICAgICBQcm9taXNlLnJlc29sdmUoe1xuICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgcmVzdWx0OiB7IG5hbWU6IFwidGVzdC1kYXRhc2V0XCIgfSxcbiAgICAgICAgfSksXG4gICAgfSlcblxuICAgIGF3YWl0IHNhdmVQYWNrYWdlVG9Da2FuKG1vY2tQYWNrYWdlLCB7XG4gICAgICAuLi5tb2NrT3B0aW9ucyxcbiAgICAgIGFwaUtleTogXCJjdXN0b20tYXBpLWtleVwiLFxuICAgIH0pXG5cbiAgICBjb25zdCBmaXJzdENhbGwgPSBmZXRjaE1vY2subW9jay5jYWxsc1swXVxuICAgIGV4cGVjdChmaXJzdENhbGwpLnRvQmVEZWZpbmVkKClcbiAgICBpZiAoIWZpcnN0Q2FsbCkgcmV0dXJuXG5cbiAgICBjb25zdCBoZWFkZXJzID0gZmlyc3RDYWxsWzFdLmhlYWRlcnNcbiAgICBleHBlY3QoaGVhZGVycy5BdXRob3JpemF0aW9uKS50b0VxdWFsKFwiY3VzdG9tLWFwaS1rZXlcIilcbiAgfSlcbn0pXG4iXX0=
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { DatasetPlugin } from "../../plugin.ts";
|
|
2
|
+
export declare class CkanPlugin implements DatasetPlugin {
|
|
3
|
+
loadPackage(source: string): Promise<{
|
|
4
|
+
[x: `${string}:${string}`]: any;
|
|
5
|
+
$schema?: string;
|
|
6
|
+
resources: import("@frictionless-ts/metadata").Resource[];
|
|
7
|
+
name?: string;
|
|
8
|
+
title?: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
homepage?: string;
|
|
11
|
+
version?: string;
|
|
12
|
+
licenses?: import("@frictionless-ts/metadata").License[];
|
|
13
|
+
contributors?: import("@frictionless-ts/metadata").Contributor[];
|
|
14
|
+
sources?: import("@frictionless-ts/metadata").Source[];
|
|
15
|
+
keywords?: string[];
|
|
16
|
+
created?: string;
|
|
17
|
+
image?: string;
|
|
18
|
+
} | undefined>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { isRemotePath } from "@frictionless-ts/metadata";
|
|
2
|
+
import { loadPackageFromCkan } from "./package/load.js";
|
|
3
|
+
export class CkanPlugin {
|
|
4
|
+
async loadPackage(source) {
|
|
5
|
+
const isCkan = getIsCkan(source);
|
|
6
|
+
if (!isCkan)
|
|
7
|
+
return undefined;
|
|
8
|
+
const dataPackage = await loadPackageFromCkan(source);
|
|
9
|
+
return dataPackage;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function getIsCkan(path) {
|
|
13
|
+
const isRemote = isRemotePath(path);
|
|
14
|
+
if (!isRemote)
|
|
15
|
+
return false;
|
|
16
|
+
return path.includes("/dataset/");
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vcGx1Z2lucy9ja2FuL3BsdWdpbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sMkJBQTJCLENBQUE7QUFFeEQsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFFdkQsTUFBTSxPQUFPLFVBQVU7SUFDckIsS0FBSyxDQUFDLFdBQVcsQ0FBQyxNQUFjO1FBQzlCLE1BQU0sTUFBTSxHQUFHLFNBQVMsQ0FBQyxNQUFNLENBQUMsQ0FBQTtRQUNoQyxJQUFJLENBQUMsTUFBTTtZQUFFLE9BQU8sU0FBUyxDQUFBO1FBRTdCLE1BQU0sV0FBVyxHQUFHLE1BQU0sbUJBQW1CLENBQUMsTUFBTSxDQUFDLENBQUE7UUFDckQsT0FBTyxXQUFXLENBQUE7SUFDcEIsQ0FBQztDQUNGO0FBRUQsU0FBUyxTQUFTLENBQUMsSUFBWTtJQUM3QixNQUFNLFFBQVEsR0FBRyxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUE7SUFDbkMsSUFBSSxDQUFDLFFBQVE7UUFBRSxPQUFPLEtBQUssQ0FBQTtJQUUzQixPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLENBQUE7QUFDbkMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGlzUmVtb3RlUGF0aCB9IGZyb20gXCJAZnJpY3Rpb25sZXNzLXRzL21ldGFkYXRhXCJcbmltcG9ydCB0eXBlIHsgRGF0YXNldFBsdWdpbiB9IGZyb20gXCIuLi8uLi9wbHVnaW4udHNcIlxuaW1wb3J0IHsgbG9hZFBhY2thZ2VGcm9tQ2thbiB9IGZyb20gXCIuL3BhY2thZ2UvbG9hZC50c1wiXG5cbmV4cG9ydCBjbGFzcyBDa2FuUGx1Z2luIGltcGxlbWVudHMgRGF0YXNldFBsdWdpbiB7XG4gIGFzeW5jIGxvYWRQYWNrYWdlKHNvdXJjZTogc3RyaW5nKSB7XG4gICAgY29uc3QgaXNDa2FuID0gZ2V0SXNDa2FuKHNvdXJjZSlcbiAgICBpZiAoIWlzQ2thbikgcmV0dXJuIHVuZGVmaW5lZFxuXG4gICAgY29uc3QgZGF0YVBhY2thZ2UgPSBhd2FpdCBsb2FkUGFja2FnZUZyb21Da2FuKHNvdXJjZSlcbiAgICByZXR1cm4gZGF0YVBhY2thZ2VcbiAgfVxufVxuXG5mdW5jdGlvbiBnZXRJc0NrYW4ocGF0aDogc3RyaW5nKSB7XG4gIGNvbnN0IGlzUmVtb3RlID0gaXNSZW1vdGVQYXRoKHBhdGgpXG4gIGlmICghaXNSZW1vdGUpIHJldHVybiBmYWxzZVxuXG4gIHJldHVybiBwYXRoLmluY2x1ZGVzKFwiL2RhdGFzZXQvXCIpXG59XG4iXX0=
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import * as packageModule from "./package/load.js";
|
|
3
|
+
import { CkanPlugin } from "./plugin.js";
|
|
4
|
+
vi.mock("./package/load.ts", () => ({
|
|
5
|
+
loadPackageFromCkan: vi.fn(),
|
|
6
|
+
}));
|
|
7
|
+
describe("CkanPlugin", () => {
|
|
8
|
+
let plugin;
|
|
9
|
+
let mockLoadPackageFromCkan;
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
plugin = new CkanPlugin();
|
|
12
|
+
mockLoadPackageFromCkan = vi.mocked(packageModule.loadPackageFromCkan);
|
|
13
|
+
vi.clearAllMocks();
|
|
14
|
+
});
|
|
15
|
+
describe("loadPackage", () => {
|
|
16
|
+
it("should load package from ckan url with /dataset/ path", async () => {
|
|
17
|
+
const mockPackage = {
|
|
18
|
+
name: "test-package",
|
|
19
|
+
resources: [{ name: "test", data: [] }],
|
|
20
|
+
};
|
|
21
|
+
mockLoadPackageFromCkan.mockResolvedValue(mockPackage);
|
|
22
|
+
const result = await plugin.loadPackage("https://data.example.com/dataset/test-dataset");
|
|
23
|
+
expect(mockLoadPackageFromCkan).toHaveBeenCalledWith("https://data.example.com/dataset/test-dataset");
|
|
24
|
+
expect(result).toEqual(mockPackage);
|
|
25
|
+
});
|
|
26
|
+
it("should return undefined for urls without /dataset/", async () => {
|
|
27
|
+
const result = await plugin.loadPackage("https://example.com/data");
|
|
28
|
+
expect(mockLoadPackageFromCkan).not.toHaveBeenCalled();
|
|
29
|
+
expect(result).toBeUndefined();
|
|
30
|
+
});
|
|
31
|
+
it("should return undefined for local paths", async () => {
|
|
32
|
+
const result = await plugin.loadPackage("./data");
|
|
33
|
+
expect(mockLoadPackageFromCkan).not.toHaveBeenCalled();
|
|
34
|
+
expect(result).toBeUndefined();
|
|
35
|
+
});
|
|
36
|
+
it("should return undefined for github urls", async () => {
|
|
37
|
+
const result = await plugin.loadPackage("https://github.com/owner/repo");
|
|
38
|
+
expect(mockLoadPackageFromCkan).not.toHaveBeenCalled();
|
|
39
|
+
expect(result).toBeUndefined();
|
|
40
|
+
});
|
|
41
|
+
it("should handle ckan urls with additional path segments", async () => {
|
|
42
|
+
const mockPackage = {
|
|
43
|
+
name: "test-package",
|
|
44
|
+
resources: [{ name: "test", data: [] }],
|
|
45
|
+
};
|
|
46
|
+
mockLoadPackageFromCkan.mockResolvedValue(mockPackage);
|
|
47
|
+
const result = await plugin.loadPackage("https://data.example.com/dataset/test-dataset/resource/123");
|
|
48
|
+
expect(mockLoadPackageFromCkan).toHaveBeenCalledWith("https://data.example.com/dataset/test-dataset/resource/123");
|
|
49
|
+
expect(result).toEqual(mockPackage);
|
|
50
|
+
});
|
|
51
|
+
it("should handle ckan urls with query parameters", async () => {
|
|
52
|
+
const mockPackage = {
|
|
53
|
+
name: "test-package",
|
|
54
|
+
resources: [{ name: "test", data: [] }],
|
|
55
|
+
};
|
|
56
|
+
mockLoadPackageFromCkan.mockResolvedValue(mockPackage);
|
|
57
|
+
const result = await plugin.loadPackage("https://data.example.com/dataset/test-dataset?id=456");
|
|
58
|
+
expect(mockLoadPackageFromCkan).toHaveBeenCalledWith("https://data.example.com/dataset/test-dataset?id=456");
|
|
59
|
+
expect(result).toEqual(mockPackage);
|
|
60
|
+
});
|
|
61
|
+
it("should handle http ckan urls", async () => {
|
|
62
|
+
const mockPackage = {
|
|
63
|
+
name: "test-package",
|
|
64
|
+
resources: [{ name: "test", data: [] }],
|
|
65
|
+
};
|
|
66
|
+
mockLoadPackageFromCkan.mockResolvedValue(mockPackage);
|
|
67
|
+
const result = await plugin.loadPackage("http://data.example.com/dataset/test-dataset");
|
|
68
|
+
expect(mockLoadPackageFromCkan).toHaveBeenCalledWith("http://data.example.com/dataset/test-dataset");
|
|
69
|
+
expect(result).toEqual(mockPackage);
|
|
70
|
+
});
|
|
71
|
+
it("should return undefined for zenodo urls", async () => {
|
|
72
|
+
const result = await plugin.loadPackage("https://zenodo.org/record/123");
|
|
73
|
+
expect(mockLoadPackageFromCkan).not.toHaveBeenCalled();
|
|
74
|
+
expect(result).toBeUndefined();
|
|
75
|
+
});
|
|
76
|
+
it("should return undefined for urls with dataset in query params only", async () => {
|
|
77
|
+
const result = await plugin.loadPackage("https://example.com/api?name=dataset");
|
|
78
|
+
expect(mockLoadPackageFromCkan).not.toHaveBeenCalled();
|
|
79
|
+
expect(result).toBeUndefined();
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLnNwZWMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9wbHVnaW5zL2NrYW4vcGx1Z2luLnNwZWMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLFVBQVUsRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsTUFBTSxRQUFRLENBQUE7QUFDN0QsT0FBTyxLQUFLLGFBQWEsTUFBTSxtQkFBbUIsQ0FBQTtBQUNsRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBRXhDLEVBQUUsQ0FBQyxJQUFJLENBQUMsbUJBQW1CLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztJQUNsQyxtQkFBbUIsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFO0NBQzdCLENBQUMsQ0FBQyxDQUFBO0FBRUgsUUFBUSxDQUFDLFlBQVksRUFBRSxHQUFHLEVBQUU7SUFDMUIsSUFBSSxNQUFrQixDQUFBO0lBQ3RCLElBQUksdUJBQWlELENBQUE7SUFFckQsVUFBVSxDQUFDLEdBQUcsRUFBRTtRQUNkLE1BQU0sR0FBRyxJQUFJLFVBQVUsRUFBRSxDQUFBO1FBQ3pCLHVCQUF1QixHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLG1CQUFtQixDQUFDLENBQUE7UUFDdEUsRUFBRSxDQUFDLGFBQWEsRUFBRSxDQUFBO0lBQ3BCLENBQUMsQ0FBQyxDQUFBO0lBRUYsUUFBUSxDQUFDLGFBQWEsRUFBRSxHQUFHLEVBQUU7UUFDM0IsRUFBRSxDQUFDLHVEQUF1RCxFQUFFLEtBQUssSUFBSSxFQUFFO1lBQ3JFLE1BQU0sV0FBVyxHQUFZO2dCQUMzQixJQUFJLEVBQUUsY0FBYztnQkFDcEIsU0FBUyxFQUFFLENBQUMsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsQ0FBQzthQUN4QyxDQUFBO1lBQ0QsdUJBQXVCLENBQUMsaUJBQWlCLENBQUMsV0FBVyxD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ZSB9IGZyb20gXCJAZnJpY3Rpb25sZXNzLXRzL21ldGFkYXRhXCJcbmltcG9ydCB7IGJlZm9yZUVhY2gsIGRlc2NyaWJlLCBleHBlY3QsIGl0LCB2aSB9IGZyb20gXCJ2aXRlc3RcIlxuaW1wb3J0ICogYXMgcGFja2FnZU1vZHVsZSBmcm9tIFwiLi9wYWNrYWdlL2xvYWQudHNcIlxuaW1wb3J0IHsgQ2thblBsdWdpbiB9IGZyb20gXCIuL3BsdWdpbi50c1wiXG5cbnZpLm1vY2soXCIuL3BhY2thZ2UvbG9hZC50c1wiLCAoKSA9PiAoe1xuICBsb2FkUGFja2FnZUZyb21Da2FuOiB2aS5mbigpLFxufSkpXG5cbmRlc2NyaWJlKFwiQ2thblBsdWdpblwiLCAoKSA9PiB7XG4gIGxldCBwbHVnaW46IENrYW5QbHVnaW5cbiAgbGV0IG1vY2tMb2FkUGFja2FnZUZyb21Da2FuOiBSZXR1cm5UeXBlPHR5cGVvZiB2aS5mbj5cblxuICBiZWZvcmVFYWNoKCgpID0+IHtcbiAgICBwbHVnaW4gPSBuZXcgQ2thblBsdWdpbigpXG4gICAgbW9ja0xvYWRQYWNrYWdlRnJvbUNrYW4gPSB2aS5tb2NrZWQocGFja2FnZU1vZHVsZS5sb2FkUGFja2FnZUZyb21Da2FuKVxuICAgIHZpLmNsZWFyQWxsTW9ja3MoKVxuICB9KVxuXG4gIGRlc2NyaWJlKFwibG9hZFBhY2thZ2VcIiwgKCkgPT4ge1xuICAgIGl0KFwic2hvdWxkIGxvYWQgcGFja2FnZSBmcm9tIGNrYW4gdXJsIHdpdGggL2RhdGFzZXQvIHBhdGhcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgbW9ja1BhY2thZ2U6IFBhY2thZ2UgPSB7XG4gICAgICAgIG5hbWU6IFwidGVzdC1wYWNrYWdlXCIsXG4gICAgICAgIHJlc291cmNlczogW3sgbmFtZTogXCJ0ZXN0XCIsIGRhdGE6IFtdIH1dLFxuICAgICAgfVxuICAgICAgbW9ja0xvYWRQYWNrYWdlRnJvbUNrYW4ubW9ja1Jlc29sdmVkVmFsdWUobW9ja1BhY2thZ2UpXG5cbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBsdWdpbi5sb2FkUGFja2FnZShcbiAgICAgICAgXCJodHRwczovL2RhdGEuZXhhbXBsZS5jb20vZGF0YXNldC90ZXN0LWRhdGFzZXRcIixcbiAgICAgIClcblxuICAgICAgZXhwZWN0KG1vY2tMb2FkUGFja2FnZUZyb21Da2FuKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChcbiAgICAgICAgXCJodHRwczovL2RhdGEuZXhhbXBsZS5jb20vZGF0YXNldC90ZXN0LWRhdGFzZXRcIixcbiAgICAgIClcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvRXF1YWwobW9ja1BhY2thZ2UpXG4gICAgfSlcblxuICAgIGl0KFwic2hvdWxkIHJldHVybiB1bmRlZmluZWQgZm9yIHVybHMgd2l0aG91dCAvZGF0YXNldC9cIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcGx1Z2luLmxvYWRQYWNrYWdlKFwiaHR0cHM6Ly9leGFtcGxlLmNvbS9kYXRhXCIpXG5cbiAgICAgIGV4cGVjdChtb2NrTG9hZFBhY2thZ2VGcm9tQ2thbikubm90LnRvSGF2ZUJlZW5DYWxsZWQoKVxuICAgICAgZXhwZWN0KHJlc3VsdCkudG9CZVVuZGVmaW5lZCgpXG4gICAgfSlcblxuICAgIGl0KFwic2hvdWxkIHJldHVybiB1bmRlZmluZWQgZm9yIGxvY2FsIHBhdGhzXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBsdWdpbi5sb2FkUGFja2FnZShcIi4vZGF0YVwiKVxuXG4gICAgICBleHBlY3QobW9ja0xvYWRQYWNrYWdlRnJvbUNrYW4pLm5vdC50b0hhdmVCZWVuQ2FsbGVkKClcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvQmVVbmRlZmluZWQoKVxuICAgIH0pXG5cbiAgICBpdChcInNob3VsZCByZXR1cm4gdW5kZWZpbmVkIGZvciBnaXRodWIgdXJsc1wiLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwbHVnaW4ubG9hZFBhY2thZ2UoXCJodHRwczovL2dpdGh1Yi5jb20vb3duZXIvcmVwb1wiKVxuXG4gICAgICBleHBlY3QobW9ja0xvYWRQYWNrYWdlRnJvbUNrYW4pLm5vdC50b0hhdmVCZWVuQ2FsbGVkKClcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvQmVVbmRlZmluZWQoKVxuICAgIH0pXG5cbiAgICBpdChcInNob3VsZCBoYW5kbGUgY2thbiB1cmxzIHdpdGggYWRkaXRpb25hbCBwYXRoIHNlZ21lbnRzXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IG1vY2tQYWNrYWdlOiBQYWNrYWdlID0ge1xuICAgICAgICBuYW1lOiBcInRlc3QtcGFja2FnZVwiLFxuICAgICAgICByZXNvdXJjZXM6IFt7IG5hbWU6IFwidGVzdFwiLCBkYXRhOiBbXSB9XSxcbiAgICAgIH1cbiAgICAgIG1vY2tMb2FkUGFja2FnZUZyb21Da2FuLm1vY2tSZXNvbHZlZFZhbHVlKG1vY2tQYWNrYWdlKVxuXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwbHVnaW4ubG9hZFBhY2thZ2UoXG4gICAgICAgIFwiaHR0cHM6Ly9kYXRhLmV4YW1wbGUuY29tL2RhdGFzZXQvdGVzdC1kYXRhc2V0L3Jlc291cmNlLzEyM1wiLFxuICAgICAgKVxuXG4gICAgICBleHBlY3QobW9ja0xvYWRQYWNrYWdlRnJvbUNrYW4pLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKFxuICAgICAgICBcImh0dHBzOi8vZGF0YS5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldC9yZXNvdXJjZS8xMjNcIixcbiAgICAgIClcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvRXF1YWwobW9ja1BhY2thZ2UpXG4gICAgfSlcblxuICAgIGl0KFwic2hvdWxkIGhhbmRsZSBja2FuIHVybHMgd2l0aCBxdWVyeSBwYXJhbWV0ZXJzXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IG1vY2tQYWNrYWdlOiBQYWNrYWdlID0ge1xuICAgICAgICBuYW1lOiBcInRlc3QtcGFja2FnZVwiLFxuICAgICAgICByZXNvdXJjZXM6IFt7IG5hbWU6IFwidGVzdFwiLCBkYXRhOiBbXSB9XSxcbiAgICAgIH1cbiAgICAgIG1vY2tMb2FkUGFja2FnZUZyb21Da2FuLm1vY2tSZXNvbHZlZFZhbHVlKG1vY2tQYWNrYWdlKVxuXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwbHVnaW4ubG9hZFBhY2thZ2UoXG4gICAgICAgIFwiaHR0cHM6Ly9kYXRhLmV4YW1wbGUuY29tL2RhdGFzZXQvdGVzdC1kYXRhc2V0P2lkPTQ1NlwiLFxuICAgICAgKVxuXG4gICAgICBleHBlY3QobW9ja0xvYWRQYWNrYWdlRnJvbUNrYW4pLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKFxuICAgICAgICBcImh0dHBzOi8vZGF0YS5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldD9pZD00NTZcIixcbiAgICAgIClcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvRXF1YWwobW9ja1BhY2thZ2UpXG4gICAgfSlcblxuICAgIGl0KFwic2hvdWxkIGhhbmRsZSBodHRwIGNrYW4gdXJsc1wiLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBtb2NrUGFja2FnZTogUGFja2FnZSA9IHtcbiAgICAgICAgbmFtZTogXCJ0ZXN0LXBhY2thZ2VcIixcbiAgICAgICAgcmVzb3VyY2VzOiBbeyBuYW1lOiBcInRlc3RcIiwgZGF0YTogW10gfV0sXG4gICAgICB9XG4gICAgICBtb2NrTG9hZFBhY2thZ2VGcm9tQ2thbi5tb2NrUmVzb2x2ZWRWYWx1ZShtb2NrUGFja2FnZSlcblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcGx1Z2luLmxvYWRQYWNrYWdlKFxuICAgICAgICBcImh0dHA6Ly9kYXRhLmV4YW1wbGUuY29tL2RhdGFzZXQvdGVzdC1kYXRhc2V0XCIsXG4gICAgICApXG5cbiAgICAgIGV4cGVjdChtb2NrTG9hZFBhY2thZ2VGcm9tQ2thbikudG9IYXZlQmVlbkNhbGxlZFdpdGgoXG4gICAgICAgIFwiaHR0cDovL2RhdGEuZXhhbXBsZS5jb20vZGF0YXNldC90ZXN0LWRhdGFzZXRcIixcbiAgICAgIClcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvRXF1YWwobW9ja1BhY2thZ2UpXG4gICAgfSlcblxuICAgIGl0KFwic2hvdWxkIHJldHVybiB1bmRlZmluZWQgZm9yIHplbm9kbyB1cmxzXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBsdWdpbi5sb2FkUGFja2FnZShcImh0dHBzOi8vemVub2RvLm9yZy9yZWNvcmQvMTIzXCIpXG5cbiAgICAgIGV4cGVjdChtb2NrTG9hZFBhY2thZ2VGcm9tQ2thbikubm90LnRvSGF2ZUJlZW5DYWxsZWQoKVxuICAgICAgZXhwZWN0KHJlc3VsdCkudG9CZVVuZGVmaW5lZCgpXG4gICAgfSlcblxuICAgIGl0KFwic2hvdWxkIHJldHVybiB1bmRlZmluZWQgZm9yIHVybHMgd2l0aCBkYXRhc2V0IGluIHF1ZXJ5IHBhcmFtcyBvbmx5XCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBsdWdpbi5sb2FkUGFja2FnZShcbiAgICAgICAgXCJodHRwczovL2V4YW1wbGUuY29tL2FwaT9uYW1lPWRhdGFzZXRcIixcbiAgICAgIClcblxuICAgICAgZXhwZWN0KG1vY2tMb2FkUGFja2FnZUZyb21Da2FuKS5ub3QudG9IYXZlQmVlbkNhbGxlZCgpXG4gICAgICBleHBlY3QocmVzdWx0KS50b0JlVW5kZWZpbmVkKClcbiAgICB9KVxuICB9KVxufSlcbiJdfQ==
|