@frictionless-ts/metadata 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.
Files changed (312) hide show
  1. package/README.md +3 -0
  2. package/build/assets/dialect-1.0.json +58 -0
  3. package/build/assets/dialect-2.0.json +98 -0
  4. package/build/assets/package-1.0.json +1517 -0
  5. package/build/assets/package-2.0.json +2168 -0
  6. package/build/assets/resource-1.0.json +1353 -0
  7. package/build/assets/resource-2.0.json +1987 -0
  8. package/build/assets/schema-1.0.json +1126 -0
  9. package/build/assets/schema-2.0.json +1715 -0
  10. package/build/descriptor/Descriptor.d.ts +2 -0
  11. package/build/descriptor/Descriptor.js +4 -0
  12. package/build/descriptor/index.d.ts +6 -0
  13. package/build/descriptor/index.js +6 -0
  14. package/build/descriptor/load.d.ts +8 -0
  15. package/build/descriptor/load.js +36 -0
  16. package/build/descriptor/load.spec.d.ts +1 -0
  17. package/build/descriptor/load.spec.js +44 -0
  18. package/build/descriptor/process/parse.d.ts +2 -0
  19. package/build/descriptor/process/parse.js +8 -0
  20. package/build/descriptor/process/stringify.d.ts +2 -0
  21. package/build/descriptor/process/stringify.js +4 -0
  22. package/build/descriptor/save.d.ts +9 -0
  23. package/build/descriptor/save.js +19 -0
  24. package/build/descriptor/save.spec.d.ts +1 -0
  25. package/build/descriptor/save.spec.js +99 -0
  26. package/build/dialect/Dialect.d.ts +89 -0
  27. package/build/dialect/Dialect.js +2 -0
  28. package/build/dialect/assert.d.ts +6 -0
  29. package/build/dialect/assert.js +12 -0
  30. package/build/dialect/assert.spec.d.ts +1 -0
  31. package/build/dialect/assert.spec.js +22 -0
  32. package/build/dialect/convert/fromDescriptor.d.ts +2 -0
  33. package/build/dialect/convert/fromDescriptor.js +20 -0
  34. package/build/dialect/convert/toDescriptor.d.ts +3 -0
  35. package/build/dialect/convert/toDescriptor.js +5 -0
  36. package/build/dialect/index.d.ts +8 -0
  37. package/build/dialect/index.js +8 -0
  38. package/build/dialect/load.d.ts +5 -0
  39. package/build/dialect/load.js +12 -0
  40. package/build/dialect/load.spec.d.ts +1 -0
  41. package/build/dialect/load.spec.js +18 -0
  42. package/build/dialect/resolve.d.ts +2 -0
  43. package/build/dialect/resolve.js +11 -0
  44. package/build/dialect/save.d.ts +9 -0
  45. package/build/dialect/save.js +16 -0
  46. package/build/dialect/save.spec.d.ts +1 -0
  47. package/build/dialect/save.spec.js +52 -0
  48. package/build/dialect/validate.d.ts +10 -0
  49. package/build/dialect/validate.js +25 -0
  50. package/build/dialect/validate.spec.d.ts +1 -0
  51. package/build/dialect/validate.spec.js +28 -0
  52. package/build/error/Bound.d.ts +4 -0
  53. package/build/error/Bound.js +2 -0
  54. package/build/error/Error.d.ts +3 -0
  55. package/build/error/Error.js +2 -0
  56. package/build/error/Unbound.d.ts +6 -0
  57. package/build/error/Unbound.js +2 -0
  58. package/build/error/index.d.ts +16 -0
  59. package/build/error/index.js +2 -0
  60. package/build/error/types/Base.d.ts +3 -0
  61. package/build/error/types/Base.js +2 -0
  62. package/build/error/types/Bytes.d.ts +6 -0
  63. package/build/error/types/Bytes.js +2 -0
  64. package/build/error/types/Cell.d.ts +56 -0
  65. package/build/error/types/Cell.js +2 -0
  66. package/build/error/types/Data.d.ts +5 -0
  67. package/build/error/types/Data.js +2 -0
  68. package/build/error/types/Document.d.ts +7 -0
  69. package/build/error/types/Document.js +2 -0
  70. package/build/error/types/Encoding.d.ts +6 -0
  71. package/build/error/types/Encoding.js +2 -0
  72. package/build/error/types/Field.d.ts +15 -0
  73. package/build/error/types/Field.js +2 -0
  74. package/build/error/types/Fields.d.ts +11 -0
  75. package/build/error/types/Fields.js +2 -0
  76. package/build/error/types/File.d.ts +4 -0
  77. package/build/error/types/File.js +2 -0
  78. package/build/error/types/ForeignKey.d.ts +7 -0
  79. package/build/error/types/ForeignKey.js +2 -0
  80. package/build/error/types/Hash.d.ts +6 -0
  81. package/build/error/types/Hash.js +2 -0
  82. package/build/error/types/Metadata.d.ts +9 -0
  83. package/build/error/types/Metadata.js +2 -0
  84. package/build/error/types/Row.d.ts +9 -0
  85. package/build/error/types/Row.js +2 -0
  86. package/build/error/types/Table.d.ts +6 -0
  87. package/build/error/types/Table.js +2 -0
  88. package/build/field/Field.d.ts +5 -0
  89. package/build/field/Field.js +2 -0
  90. package/build/field/Type.d.ts +2 -0
  91. package/build/field/Type.js +2 -0
  92. package/build/field/convert/fromDescriptor.d.ts +2 -0
  93. package/build/field/convert/fromDescriptor.js +61 -0
  94. package/build/field/convert/fromDescriptor.spec.d.ts +1 -0
  95. package/build/field/convert/fromDescriptor.spec.js +241 -0
  96. package/build/field/convert/toDescriptor.d.ts +3 -0
  97. package/build/field/convert/toDescriptor.js +5 -0
  98. package/build/field/convert/toDescriptor.spec.d.ts +1 -0
  99. package/build/field/convert/toDescriptor.spec.js +291 -0
  100. package/build/field/index.d.ts +5 -0
  101. package/build/field/index.js +3 -0
  102. package/build/field/types/Any.d.ts +20 -0
  103. package/build/field/types/Any.js +2 -0
  104. package/build/field/types/Array.d.ts +32 -0
  105. package/build/field/types/Array.js +2 -0
  106. package/build/field/types/Base.d.ts +60 -0
  107. package/build/field/types/Base.js +2 -0
  108. package/build/field/types/Boolean.d.ts +28 -0
  109. package/build/field/types/Boolean.js +2 -0
  110. package/build/field/types/Date.d.ts +43 -0
  111. package/build/field/types/Date.js +2 -0
  112. package/build/field/types/Datetime.d.ts +43 -0
  113. package/build/field/types/Datetime.js +2 -0
  114. package/build/field/types/Duration.d.ts +28 -0
  115. package/build/field/types/Duration.js +2 -0
  116. package/build/field/types/Geojson.d.ts +30 -0
  117. package/build/field/types/Geojson.js +2 -0
  118. package/build/field/types/Geopoint.d.ts +27 -0
  119. package/build/field/types/Geopoint.js +2 -0
  120. package/build/field/types/Integer.d.ts +57 -0
  121. package/build/field/types/Integer.js +2 -0
  122. package/build/field/types/List.d.ts +36 -0
  123. package/build/field/types/List.js +2 -0
  124. package/build/field/types/Number.d.ts +48 -0
  125. package/build/field/types/Number.js +2 -0
  126. package/build/field/types/Object.d.ts +32 -0
  127. package/build/field/types/Object.js +2 -0
  128. package/build/field/types/String.d.ts +51 -0
  129. package/build/field/types/String.js +2 -0
  130. package/build/field/types/Time.d.ts +43 -0
  131. package/build/field/types/Time.js +2 -0
  132. package/build/field/types/Year.d.ts +36 -0
  133. package/build/field/types/Year.js +2 -0
  134. package/build/field/types/Yearmonth.d.ts +36 -0
  135. package/build/field/types/Yearmonth.js +2 -0
  136. package/build/field/types/index.d.ts +16 -0
  137. package/build/field/types/index.js +17 -0
  138. package/build/index.d.ts +112 -0
  139. package/build/index.js +32 -0
  140. package/build/json/Schema.d.ts +2 -0
  141. package/build/json/Schema.js +2 -0
  142. package/build/json/Value.d.ts +1 -0
  143. package/build/json/Value.js +2 -0
  144. package/build/json/ajv.d.ts +2 -0
  145. package/build/json/ajv.js +10 -0
  146. package/build/json/assert.d.ts +2 -0
  147. package/build/json/assert.js +10 -0
  148. package/build/json/cache.d.ts +2 -0
  149. package/build/json/cache.js +5 -0
  150. package/build/json/index.d.ts +5 -0
  151. package/build/json/index.js +4 -0
  152. package/build/json/inspect/schema.d.ts +4 -0
  153. package/build/json/inspect/schema.js +10 -0
  154. package/build/json/inspect/schema.spec.d.ts +1 -0
  155. package/build/json/inspect/schema.spec.js +132 -0
  156. package/build/json/inspect/value.d.ts +11 -0
  157. package/build/json/inspect/value.js +21 -0
  158. package/build/json/inspect/value.spec.d.ts +1 -0
  159. package/build/json/inspect/value.spec.js +121 -0
  160. package/build/json/load.d.ts +3 -0
  161. package/build/json/load.js +13 -0
  162. package/build/json/resolve.d.ts +2 -0
  163. package/build/json/resolve.js +11 -0
  164. package/build/metadata/Metadata.d.ts +3 -0
  165. package/build/metadata/Metadata.js +2 -0
  166. package/build/metadata/index.d.ts +1 -0
  167. package/build/metadata/index.js +2 -0
  168. package/build/package/Contributor.d.ts +21 -0
  169. package/build/package/Contributor.js +2 -0
  170. package/build/package/Package.d.ts +64 -0
  171. package/build/package/Package.js +2 -0
  172. package/build/package/assert.d.ts +8 -0
  173. package/build/package/assert.js +12 -0
  174. package/build/package/assert.spec.d.ts +1 -0
  175. package/build/package/assert.spec.js +26 -0
  176. package/build/package/convert/fromDescriptor.d.ts +4 -0
  177. package/build/package/convert/fromDescriptor.js +36 -0
  178. package/build/package/convert/toDescriptor.d.ts +5 -0
  179. package/build/package/convert/toDescriptor.js +7 -0
  180. package/build/package/index.d.ts +8 -0
  181. package/build/package/index.js +7 -0
  182. package/build/package/load.d.ts +5 -0
  183. package/build/package/load.js +14 -0
  184. package/build/package/load.spec.d.ts +1 -0
  185. package/build/package/load.spec.js +28 -0
  186. package/build/package/save.d.ts +9 -0
  187. package/build/package/save.js +18 -0
  188. package/build/package/save.spec.d.ts +1 -0
  189. package/build/package/save.spec.js +311 -0
  190. package/build/package/validate.d.ts +12 -0
  191. package/build/package/validate.js +27 -0
  192. package/build/package/validate.spec.d.ts +1 -0
  193. package/build/package/validate.spec.js +41 -0
  194. package/build/path/basepath.d.ts +2 -0
  195. package/build/path/basepath.js +25 -0
  196. package/build/path/basepath.spec.d.ts +1 -0
  197. package/build/path/basepath.spec.js +55 -0
  198. package/build/path/denormalize.d.ts +3 -0
  199. package/build/path/denormalize.js +29 -0
  200. package/build/path/denormalize.spec.d.ts +1 -0
  201. package/build/path/denormalize.spec.js +45 -0
  202. package/build/path/index.d.ts +5 -0
  203. package/build/path/index.js +6 -0
  204. package/build/path/normalize.d.ts +6 -0
  205. package/build/path/normalize.js +54 -0
  206. package/build/path/normalize.spec.d.ts +1 -0
  207. package/build/path/normalize.spec.js +71 -0
  208. package/build/path/path.d.ts +5 -0
  209. package/build/path/path.js +48 -0
  210. package/build/path/path.spec.d.ts +1 -0
  211. package/build/path/path.spec.js +111 -0
  212. package/build/platform/index.d.ts +1 -0
  213. package/build/platform/index.js +2 -0
  214. package/build/platform/node.d.ts +130 -0
  215. package/build/platform/node.js +10 -0
  216. package/build/platform/node.spec.d.ts +1 -0
  217. package/build/platform/node.spec.js +16 -0
  218. package/build/profile/@minify.d.ts +1 -0
  219. package/build/profile/@minify.js +58 -0
  220. package/build/profile/Profile.d.ts +9 -0
  221. package/build/profile/Profile.js +2 -0
  222. package/build/profile/assert.d.ts +6 -0
  223. package/build/profile/assert.js +36 -0
  224. package/build/profile/assert.spec.d.ts +1 -0
  225. package/build/profile/assert.spec.js +115 -0
  226. package/build/profile/index.d.ts +2 -0
  227. package/build/profile/index.js +2 -0
  228. package/build/profile/load.d.ts +4 -0
  229. package/build/profile/load.js +12 -0
  230. package/build/profile/registry.d.ts +2 -0
  231. package/build/profile/registry.js +83 -0
  232. package/build/profile/resolve.d.ts +2 -0
  233. package/build/profile/resolve.js +8 -0
  234. package/build/profile/validate.d.ts +9 -0
  235. package/build/profile/validate.js +12 -0
  236. package/build/report/Report.d.ts +5 -0
  237. package/build/report/Report.js +2 -0
  238. package/build/report/create.d.ts +7 -0
  239. package/build/report/create.js +6 -0
  240. package/build/report/index.d.ts +2 -0
  241. package/build/report/index.js +2 -0
  242. package/build/resource/License.d.ts +18 -0
  243. package/build/resource/License.js +2 -0
  244. package/build/resource/Resource.d.ts +93 -0
  245. package/build/resource/Resource.js +2 -0
  246. package/build/resource/Source.d.ts +17 -0
  247. package/build/resource/Source.js +2 -0
  248. package/build/resource/assert.d.ts +8 -0
  249. package/build/resource/assert.js +12 -0
  250. package/build/resource/assert.spec.d.ts +1 -0
  251. package/build/resource/assert.spec.js +23 -0
  252. package/build/resource/convert/fromDescriptor.d.ts +4 -0
  253. package/build/resource/convert/fromDescriptor.js +69 -0
  254. package/build/resource/convert/toDescriptor.d.ts +5 -0
  255. package/build/resource/convert/toDescriptor.js +36 -0
  256. package/build/resource/helpers.d.ts +2 -0
  257. package/build/resource/helpers.js +6 -0
  258. package/build/resource/index.d.ts +11 -0
  259. package/build/resource/index.js +9 -0
  260. package/build/resource/infer.d.ts +3 -0
  261. package/build/resource/infer.js +35 -0
  262. package/build/resource/infer.spec.d.ts +1 -0
  263. package/build/resource/infer.spec.js +103 -0
  264. package/build/resource/load.d.ts +5 -0
  265. package/build/resource/load.js +14 -0
  266. package/build/resource/load.spec.d.ts +1 -0
  267. package/build/resource/load.spec.js +22 -0
  268. package/build/resource/save.d.ts +9 -0
  269. package/build/resource/save.js +18 -0
  270. package/build/resource/save.spec.d.ts +1 -0
  271. package/build/resource/save.spec.js +170 -0
  272. package/build/resource/validate.d.ts +13 -0
  273. package/build/resource/validate.js +57 -0
  274. package/build/resource/validate.spec.d.ts +1 -0
  275. package/build/resource/validate.spec.js +30 -0
  276. package/build/schema/ForeignKey.d.ts +23 -0
  277. package/build/schema/ForeignKey.js +2 -0
  278. package/build/schema/Schema.d.ts +56 -0
  279. package/build/schema/Schema.js +2 -0
  280. package/build/schema/assert.d.ts +6 -0
  281. package/build/schema/assert.js +12 -0
  282. package/build/schema/assert.spec.d.ts +1 -0
  283. package/build/schema/assert.spec.js +34 -0
  284. package/build/schema/convert/fromDescriptor.d.ts +2 -0
  285. package/build/schema/convert/fromDescriptor.js +70 -0
  286. package/build/schema/convert/fromJsonSchema.d.ts +3 -0
  287. package/build/schema/convert/fromJsonSchema.js +105 -0
  288. package/build/schema/convert/fromJsonSchema.spec.d.ts +1 -0
  289. package/build/schema/convert/fromJsonSchema.spec.js +156 -0
  290. package/build/schema/convert/toDescriptor.d.ts +3 -0
  291. package/build/schema/convert/toDescriptor.js +5 -0
  292. package/build/schema/convert/toJsonSchema.d.ts +3 -0
  293. package/build/schema/convert/toJsonSchema.js +173 -0
  294. package/build/schema/convert/toJsonSchema.spec.d.ts +1 -0
  295. package/build/schema/convert/toJsonSchema.spec.js +403 -0
  296. package/build/schema/index.d.ts +11 -0
  297. package/build/schema/index.js +10 -0
  298. package/build/schema/load.d.ts +5 -0
  299. package/build/schema/load.js +12 -0
  300. package/build/schema/load.spec.d.ts +1 -0
  301. package/build/schema/load.spec.js +55 -0
  302. package/build/schema/resolve.d.ts +2 -0
  303. package/build/schema/resolve.js +11 -0
  304. package/build/schema/save.d.ts +9 -0
  305. package/build/schema/save.js +16 -0
  306. package/build/schema/save.spec.d.ts +1 -0
  307. package/build/schema/save.spec.js +58 -0
  308. package/build/schema/validate.d.ts +10 -0
  309. package/build/schema/validate.js +25 -0
  310. package/build/schema/validate.spec.d.ts +1 -0
  311. package/build/schema/validate.spec.js +41 -0
  312. package/package.json +37 -0
@@ -0,0 +1,311 @@
1
+ import * as fs from "node:fs/promises";
2
+ import * as path from "node:path";
3
+ import { temporaryDirectory } from "tempy";
4
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
5
+ import { savePackageDescriptor } from "./save.js";
6
+ describe("savePackageDescriptor", () => {
7
+ let testDir;
8
+ let testPath;
9
+ let testPackage;
10
+ beforeEach(() => {
11
+ testDir = temporaryDirectory();
12
+ testPath = path.join(testDir, "datapackage.json");
13
+ testPackage = {
14
+ name: "test-package",
15
+ resources: [
16
+ {
17
+ name: "test-resource",
18
+ path: path.join(testDir, "data.csv"),
19
+ },
20
+ ],
21
+ };
22
+ });
23
+ afterEach(async () => {
24
+ try {
25
+ await fs.rm(testDir, { recursive: true, force: true });
26
+ }
27
+ catch (error) {
28
+ if (error instanceof Error && !error.message.includes("ENOENT")) {
29
+ console.error(`Failed to clean up test directory: ${testDir}`, error);
30
+ }
31
+ }
32
+ });
33
+ it("should save a package descriptor to a file and maintain its structure", async () => {
34
+ await savePackageDescriptor(testPackage, { path: testPath });
35
+ const fileExists = await fs
36
+ .stat(testPath)
37
+ .then(() => true)
38
+ .catch(() => false);
39
+ expect(fileExists).toBe(true);
40
+ const content = await fs.readFile(testPath, "utf-8");
41
+ const parsedContent = JSON.parse(content);
42
+ const { $schema, ...packageWithoutSchema } = parsedContent;
43
+ expect(packageWithoutSchema.name).toEqual(testPackage.name);
44
+ expect(packageWithoutSchema.resources).toHaveLength(1);
45
+ expect(packageWithoutSchema.resources[0].name).toBe("test-resource");
46
+ expect(packageWithoutSchema.resources[0].path).toBe("data.csv");
47
+ expect($schema).toBe("https://datapackage.org/profiles/2.0/datapackage.json");
48
+ });
49
+ it("should add $schema property if not present", async () => {
50
+ await savePackageDescriptor(testPackage, { path: testPath });
51
+ const content = await fs.readFile(testPath, "utf-8");
52
+ const parsedContent = JSON.parse(content);
53
+ expect(parsedContent.$schema).toBe("https://datapackage.org/profiles/2.0/datapackage.json");
54
+ });
55
+ it("should preserve existing $schema property", async () => {
56
+ const packageWithSchema = {
57
+ name: "test-package",
58
+ resources: [
59
+ {
60
+ name: "test-resource",
61
+ path: path.join(testDir, "data.csv"),
62
+ },
63
+ ],
64
+ $schema: "https://custom.schema.url",
65
+ };
66
+ await savePackageDescriptor(packageWithSchema, { path: testPath });
67
+ const content = await fs.readFile(testPath, "utf-8");
68
+ const parsedContent = JSON.parse(content);
69
+ expect(parsedContent.$schema).toBe("https://custom.schema.url");
70
+ });
71
+ it("should use pretty formatting with 2-space indentation", async () => {
72
+ await savePackageDescriptor(testPackage, { path: testPath });
73
+ const content = await fs.readFile(testPath, "utf-8");
74
+ const lines = content.split("\n");
75
+ expect(lines.length).toBeGreaterThan(1);
76
+ if (lines.length > 1 && lines[1]) {
77
+ expect(lines[1].startsWith(" ")).toBe(true);
78
+ }
79
+ });
80
+ it("should save package with multiple resources", async () => {
81
+ const packageWithMultipleResources = {
82
+ name: "test-package",
83
+ resources: [
84
+ {
85
+ name: "resource1",
86
+ path: path.join(testDir, "data1.csv"),
87
+ },
88
+ {
89
+ name: "resource2",
90
+ path: path.join(testDir, "data2.json"),
91
+ format: "json",
92
+ },
93
+ ],
94
+ };
95
+ await savePackageDescriptor(packageWithMultipleResources, {
96
+ path: testPath,
97
+ });
98
+ const content = await fs.readFile(testPath, "utf-8");
99
+ const parsedContent = JSON.parse(content);
100
+ expect(parsedContent.resources).toHaveLength(2);
101
+ expect(parsedContent.resources[0]?.name).toBe("resource1");
102
+ expect(parsedContent.resources[1]?.name).toBe("resource2");
103
+ });
104
+ it("should save package with resource containing schema", async () => {
105
+ const packageWithSchema = {
106
+ name: "test-package",
107
+ resources: [
108
+ {
109
+ name: "test-resource",
110
+ path: path.join(testDir, "data.csv"),
111
+ schema: {
112
+ fields: [
113
+ { name: "id", type: "integer" },
114
+ { name: "name", type: "string" },
115
+ ],
116
+ },
117
+ },
118
+ ],
119
+ };
120
+ await savePackageDescriptor(packageWithSchema, { path: testPath });
121
+ const content = await fs.readFile(testPath, "utf-8");
122
+ const parsedContent = JSON.parse(content);
123
+ expect(parsedContent.resources[0]?.schema).toEqual(packageWithSchema.resources[0]?.schema);
124
+ });
125
+ it("should save package with resource containing dialect", async () => {
126
+ const packageWithDialect = {
127
+ name: "test-package",
128
+ resources: [
129
+ {
130
+ name: "test-resource",
131
+ path: path.join(testDir, "data.csv"),
132
+ dialect: {
133
+ delimiter: ";",
134
+ lineTerminator: "\n",
135
+ },
136
+ },
137
+ ],
138
+ };
139
+ await savePackageDescriptor(packageWithDialect, { path: testPath });
140
+ const content = await fs.readFile(testPath, "utf-8");
141
+ const parsedContent = JSON.parse(content);
142
+ expect(parsedContent.resources[0]?.dialect).toEqual(packageWithDialect.resources[0]?.dialect);
143
+ });
144
+ it("should save package to a nested directory path", async () => {
145
+ const nestedPath = path.join(testDir, "nested", "dir", "datapackage.json");
146
+ const nestedPackage = {
147
+ name: "test-package",
148
+ resources: [
149
+ {
150
+ name: "test-resource",
151
+ path: path.join(testDir, "nested", "dir", "data.csv"),
152
+ },
153
+ ],
154
+ };
155
+ await savePackageDescriptor(nestedPackage, { path: nestedPath });
156
+ const fileExists = await fs
157
+ .stat(nestedPath)
158
+ .then(() => true)
159
+ .catch(() => false);
160
+ expect(fileExists).toBe(true);
161
+ const content = await fs.readFile(nestedPath, "utf-8");
162
+ const parsedContent = JSON.parse(content);
163
+ expect(parsedContent.name).toBe(nestedPackage.name);
164
+ });
165
+ it("should throw an error when file exists and overwrite is false", async () => {
166
+ await savePackageDescriptor(testPackage, { path: testPath });
167
+ await expect(savePackageDescriptor(testPackage, {
168
+ path: testPath,
169
+ overwrite: false,
170
+ })).rejects.toThrow();
171
+ });
172
+ it("should throw an error when file exists and overwrite is not specified", async () => {
173
+ await savePackageDescriptor(testPackage, { path: testPath });
174
+ await expect(savePackageDescriptor(testPackage, { path: testPath })).rejects.toThrow();
175
+ });
176
+ it("should overwrite existing file when overwrite is true", async () => {
177
+ const initialPackage = {
178
+ name: "initial",
179
+ resources: [
180
+ {
181
+ name: "resource1",
182
+ path: path.join(testDir, "data1.csv"),
183
+ },
184
+ ],
185
+ };
186
+ const updatedPackage = {
187
+ name: "updated",
188
+ resources: [
189
+ {
190
+ name: "resource2",
191
+ path: path.join(testDir, "data2.csv"),
192
+ },
193
+ ],
194
+ description: "Updated package",
195
+ };
196
+ await savePackageDescriptor(initialPackage, { path: testPath });
197
+ const initialContent = await fs.readFile(testPath, "utf-8");
198
+ const initialParsed = JSON.parse(initialContent);
199
+ expect(initialParsed.name).toBe("initial");
200
+ await savePackageDescriptor(updatedPackage, {
201
+ path: testPath,
202
+ overwrite: true,
203
+ });
204
+ const updatedContent = await fs.readFile(testPath, "utf-8");
205
+ const updatedParsed = JSON.parse(updatedContent);
206
+ expect(updatedParsed.name).toBe("updated");
207
+ expect(updatedParsed.description).toBe("Updated package");
208
+ });
209
+ it("should save package with all metadata fields", async () => {
210
+ const fullPackage = {
211
+ name: "full-package",
212
+ title: "Full Package",
213
+ description: "A package with all fields",
214
+ version: "1.0.0",
215
+ homepage: "https://example.com",
216
+ keywords: ["test", "data", "package"],
217
+ created: "2024-01-01T00:00:00Z",
218
+ image: "https://example.com/image.png",
219
+ resources: [
220
+ {
221
+ name: "test-resource",
222
+ path: path.join(testDir, "data.csv"),
223
+ },
224
+ ],
225
+ };
226
+ await savePackageDescriptor(fullPackage, { path: testPath });
227
+ const content = await fs.readFile(testPath, "utf-8");
228
+ const parsedContent = JSON.parse(content);
229
+ expect(parsedContent.name).toBe(fullPackage.name);
230
+ expect(parsedContent.title).toBe(fullPackage.title);
231
+ expect(parsedContent.description).toBe(fullPackage.description);
232
+ expect(parsedContent.version).toBe(fullPackage.version);
233
+ expect(parsedContent.homepage).toBe(fullPackage.homepage);
234
+ expect(parsedContent.keywords).toEqual(fullPackage.keywords);
235
+ expect(parsedContent.created).toBe(fullPackage.created);
236
+ expect(parsedContent.image).toBe(fullPackage.image);
237
+ });
238
+ it("should save package with contributors", async () => {
239
+ const packageWithContributors = {
240
+ name: "test-package",
241
+ resources: [
242
+ {
243
+ name: "test-resource",
244
+ path: path.join(testDir, "data.csv"),
245
+ },
246
+ ],
247
+ contributors: [
248
+ {
249
+ title: "John Doe",
250
+ email: "john@example.com",
251
+ role: "author",
252
+ },
253
+ {
254
+ title: "Jane Smith",
255
+ path: "https://example.org",
256
+ },
257
+ ],
258
+ };
259
+ await savePackageDescriptor(packageWithContributors, { path: testPath });
260
+ const content = await fs.readFile(testPath, "utf-8");
261
+ const parsedContent = JSON.parse(content);
262
+ expect(parsedContent.contributors).toHaveLength(2);
263
+ expect(parsedContent.contributors[0]?.title).toBe("John Doe");
264
+ expect(parsedContent.contributors[1]?.title).toBe("Jane Smith");
265
+ });
266
+ it("should save package with licenses", async () => {
267
+ const packageWithLicenses = {
268
+ name: "test-package",
269
+ resources: [
270
+ {
271
+ name: "test-resource",
272
+ path: path.join(testDir, "data.csv"),
273
+ },
274
+ ],
275
+ licenses: [
276
+ {
277
+ name: "MIT",
278
+ path: "https://opensource.org/licenses/MIT",
279
+ },
280
+ ],
281
+ };
282
+ await savePackageDescriptor(packageWithLicenses, { path: testPath });
283
+ const content = await fs.readFile(testPath, "utf-8");
284
+ const parsedContent = JSON.parse(content);
285
+ expect(parsedContent.licenses).toHaveLength(1);
286
+ expect(parsedContent.licenses[0]?.name).toBe("MIT");
287
+ });
288
+ it("should save package with sources", async () => {
289
+ const packageWithSources = {
290
+ name: "test-package",
291
+ resources: [
292
+ {
293
+ name: "test-resource",
294
+ path: path.join(testDir, "data.csv"),
295
+ },
296
+ ],
297
+ sources: [
298
+ {
299
+ title: "Example Source",
300
+ path: "https://example.com/data",
301
+ },
302
+ ],
303
+ };
304
+ await savePackageDescriptor(packageWithSources, { path: testPath });
305
+ const content = await fs.readFile(testPath, "utf-8");
306
+ const parsedContent = JSON.parse(content);
307
+ expect(parsedContent.sources).toHaveLength(1);
308
+ expect(parsedContent.sources[0]?.title).toBe("Example Source");
309
+ });
310
+ });
311
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2F2ZS5zcGVjLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vcGFja2FnZS9zYXZlLnNwZWMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQTtBQUN0QyxPQUFPLEtBQUssSUFBSSxNQUFNLFdBQVcsQ0FBQTtBQUNqQyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxPQUFPLENBQUE7QUFDMUMsT0FBTyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxFQUFFLEVBQUUsTUFBTSxRQUFRLENBQUE7QUFFcEUsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sV0FBVyxDQUFBO0FBRWpELFFBQVEsQ0FBQyx1QkFBdUIsRUFBRSxHQUFHLEVBQUU7SUFDckMsSUFBSSxPQUFlLENBQUE7SUFDbkIsSUFBSSxRQUFnQixDQUFBO0lBQ3BCLElBQUksV0FBb0IsQ0FBQTtJQUV4QixVQUFVLENBQUMsR0FBRyxFQUFFO1FBQ2QsT0FBTyxHQUFHLGtCQUFrQixFQUFFLENBQUE7UUFDOUIsUUFBUSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLGtCQUFrQixDQUFDLENBQUE7UUFDakQsV0FBVyxHQUFHO1lBQ1osSUFBSSxFQUFFLGNBQWM7WUFDcEIsU0FBUyxFQUFFO2dCQUNUO29CQUNFLElBQUksRUFBRSxlQUFlO29CQUNyQixJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsVUFBVSxDQUFDO2lCQUNyQzthQUNGO1NBQ0YsQ0FBQTtJQUNILENBQUMsQ0FBQyxDQUFBO0lBRUYsU0FBUyxDQUFDLEtBQUssSUFBSSxFQUFFO1FBQ25CLElBQUksQ0FBQztZQUNILE1BQU0sRUFBRSxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFBO1FBQ3hELENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsSUFBSSxLQUFLLFlBQVksS0FBSyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztnQkFDaEUsT0FBTyxDQUFDLEtBQUssQ0FBQyxzQ0FBc0MsT0FBTyxFQUFFLEVBQUUsS0FBSyxDQUFDLENBQUE7WUFDdkUsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDLENBQUMsQ0FBQTtJQUVGLEVBQUUsQ0FBQyx1RUFBdUUsRUFBRSxLQUFLLElBQUksRUFBRTtRQUNyRixNQUFNLHFCQUFxQixDQUFDLFdBQVcsRUFBRSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFBO1FBRTVELE1BQU0sVUFBVSxHQUFHLE1BQU0sRUFBRTthQUN4QixJQUFJLENBQUMsUUFBUSxDQUFDO2FBQ2QsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQzthQUNoQixLQUFLLENBQUMsR0FBRyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUE7UUFDckIsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUU3QixNQUFNLE9BQU8sR0FBRyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFBO1FBQ3BELE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUE7UUFFekMsTUFBTSxFQUFFLE9BQU8sRUFBRSxHQUFHLG9CQUFvQixFQUFFLEdBQUcsYUFBYSxDQUFBO1FBQzFELE1BQU0sQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFBO1FBQzNELE1BQU0sQ0FBQyxvQkFBb0IsQ0FBQyxTQUFTLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUE7UUFDdEQsTUFBTSxDQUFDLG9CQUFvQixDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLENBQUE7UUFDcEUsTUFBTSxDQUFDLG9CQUFvQixDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUE7UUFDL0QsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FDbEIsdURBQXVELENBQ3hELENBQUE7SUFDSCxDQUFDLENBQUMsQ0FBQTtJQUVGLEVBQUUsQ0FBQyw0Q0FBNEMsRUFBRSxLQUFLLElBQUksRUFBRTtRQUMxRCxNQUFNLHFCQUFxQixDQUFDLFdBQVcsRUFBRSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFBO1FBRTVELE1BQU0sT0FBTyxHQUFHLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsT0FBTyxDQUFDLENBQUE7UUFDcEQsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQTtRQUN6QyxNQUFNLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FDaEMsdURBQXVELENBQ3hELENBQUE7SUFDSCxDQUFDLENBQUMsQ0FBQTtJQUVGLEVBQUUsQ0FBQywyQ0FBMkMsRUFBRSxLQUFLLElBQUksRUFBRTtRQUN6RCxNQUFNLGlCQUFpQixHQUFZO1lBQ2pDLElBQUksRUFBRSxjQUFjO1lBQ3BCLFNBQVMsRUFBRTtnQkFDVDtvQkFDRSxJQUFJLEVBQUUsZUFBZTtvQkFDckIsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLFVBQVUsQ0FBQztpQkFDckM7YUFDRjtZQUNELE9BQU8sRUFBRSwyQkFBMkI7U0FDckMsQ0FBQTtRQUVELE1BQU0scUJBQXFCLENBQUMsaUJBQWlCLEVBQUUsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQTtRQUVsRSxNQUFNLE9BQU8sR0FBRyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFBO1FBQ3BELE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUE7UUFDekMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsMkJBQTJCLENBQUMsQ0FBQTtJQUNqRSxDQUFDLENBQUMsQ0FBQTtJQUVGLEVBQUUsQ0FBQyx1REFBdUQsRUFBRSxLQUFLLElBQUksRUFBRTtRQUNyRSxNQUFNLHFCQUFxQixDQUFDLFdBQVcsRUFBRSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFBO1FBRTVELE1BQU0sT0FBTyxHQUFHLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsT0FBTyxDQUFDLENBQUE7UUFDcEQsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUNqQyxNQUFNLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUMsQ0FBQTtRQUV2QyxJQUFJLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQ2pDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFBO1FBQzlDLENBQUM7SUFDSCxDQUFDLENBQUMsQ0FBQTtJQUVGLEVBQUUsQ0FBQyw2Q0FBNkMsRUFBRSxLQUFLLElBQUksRUFBRTtRQUMzRCxNQUFNLDRCQUE0QixHQUFZO1lBQzVDLElBQUksRUFBRSxjQUFjO1lBQ3BCLFNBQVMsRUFBRTtnQkFDVDtvQkFDRSxJQUFJLEVBQUUsV0FBVztvQkFDakIsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLFdBQVcsQ0FBQztpQkFDdEM7Z0JBQ0Q7b0JBQ0UsSUFBSSxFQUFFLFdBQVc7b0JBQ2pCLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxZQUFZLENBQUM7b0JBQ3RDLE1BQU0sRUFBRSxNQUFNO2lCQUNmO2FBQ0Y7U0FDRixDQUFBO1FBRUQsTUFBTSxxQkFBcUIsQ0FBQyw0QkFBNEIsRUFBRTtZQUN4RCxJQUFJLEVBQUUsUUFBUTtTQUNmLENBQUMsQ0FBQTtRQUVGLE1BQU0sT0FBTyxHQUFHLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsT0FBTyxDQUFDLENBQUE7UUFDcEQsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQTtRQUN6QyxNQUFNLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQTtRQUMvQyxNQUFNLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUE7UUFDMUQsTUFBTSxDQUFDLGFBQWEsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFBO0lBQzVELENBQUMsQ0FBQyxDQUFBO0lBRUYsRUFBRSxDQUFDLHFEQUFxRCxFQUFFLEtBQUssSUFBSSxFQUFFO1FBQ25FLE1BQU0saUJBQWlCLEdBQVk7WUFDakMsSUFBSSxFQUFFLGNBQWM7WUFDcEIsU0FBUyxFQUFFO2dCQUNUO29CQUNFLElBQUksRUFBRSxlQUFlO29CQUNyQixJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsVUFBVSxDQUFDO29CQUNwQyxNQUFNLEVBQUU7d0JBQ04sTUFBTSxFQUFFOzRCQUNOLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFOzRCQUMvQixFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRTt5QkFDakM7cUJBQ0Y7aUJBQ0Y7YUFDRjtTQUNGLENBQUE7UUFFRCxNQUFNLHFCQUFxQixDQUFDLGlCQUFpQixFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUE7UUFFbEUsTUFBTSxPQUFPLEdBQUcsTUFBTSxFQUFFLENBQUMsUUFBUSxDQUFDLFFBQVEsRUFBRSxPQUFPLENBQUMsQ0FBQTtRQUNwRCxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFBO1FBQ3pDLE1BQU0sQ0FBQyxhQUFhLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDLE9BQU8sQ0FDaEQsaUJBQWlCLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLE1BQU0sQ0FDdkMsQ0FBQTtJQUNILENBQUMsQ0FBQyxDQUFBO0lBRUYsRUFBRSxDQUFDLHNEQUFzRCxFQUFFLEtBQUssSUFBSSxFQUFFO1FBQ3BFLE1BQU0sa0JBQWtCLEdBQVk7WUFDbEMsSUFBSSxFQUFFLGNBQWM7WUFDcEIsU0FBUyxFQUFFO2dCQUNUO29CQUNFLElBQUksRUFBRSxlQUFlO29CQUNyQixJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsVUFBVSxDQUFDO29CQUNwQyxPQUFPLEVBQUU7d0JBQ1AsU0FBUyxFQUFFLEdBQUc7d0JBQ2QsY0FBYyxFQUFFLElBQUk7cUJBQ3JCO2lCQUNGO2FBQ0Y7U0FDRixDQUFBO1FBRUQsTUFBTSxxQkFBcUIsQ0FBQyxrQkFBa0IsRUFBRSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFBO1FBRW5FLE1BQU0sT0FBTyxHQUFHLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsT0FBTyxDQUFDLENBQUE7UUFDcEQsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQTtRQUN6QyxNQUFNLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxPQUFPLENBQUMsQ0FBQyxPQUFPLENBQ2pELGtCQUFrQixDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxPQUFPLENBQ3pDLENBQUE7SUFDSCxDQUFDLENBQUMsQ0FBQTtJQUVGLEVBQUUsQ0FBQyxnREFBZ0QsRUFBRSxLQUFLLElBQUksRUFBRTtRQUM5RCxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLGtCQUFrQixDQUFDLENBQUE7UUFDMUUsTUFBTSxhQUFhLEdBQVk7WUFDN0IsSUFBSSxFQUFFLGNBQWM7WUFDcEIsU0FBUyxFQUFFO2dCQUNUO29CQUNFLElBQUksRUFBRSxlQUFlO29CQUNyQixJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxVQUFVLENBQUM7aUJBQ3REO2FBQ0Y7U0FDRixDQUFBO1FBRUQsTUFBTSxxQkFBcUIsQ0FBQyxhQUFhLEVBQUUsRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLENBQUMsQ0FBQTtRQUVoRSxNQUFNLFVBQVUsR0FBRyxNQUFNLEVBQUU7YUFDeEIsSUFBSSxDQUFDLFVBQVUsQ0FBQzthQUNoQixJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDO2FBQ2hCLEtBQUssQ0FBQyxHQUFHLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQTtRQUNyQixNQUFNLENBQUMsVUFBVSxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFBO1FBRTdCLE1BQU0sT0FBTyxHQUFHLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxVQUFVLEVBQUUsT0FBTyxDQUFDLENBQUE7UUFDdEQsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQTtRQUN6QyxNQUFNLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUE7SUFDckQsQ0FBQyxDQUFDLENBQUE7SUFFRixFQUFFLENBQUMsK0RBQStELEVBQUUsS0FBSyxJQUFJLEVBQUU7UUFDN0UsTUFBTSxxQkFBcUIsQ0FBQyxXQUFXLEVBQUUsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQTtRQUU1RCxNQUFNLE1BQU0sQ0FDVixxQkFBcUIsQ0FBQyxXQUFXLEVBQUU7WUFDakMsSUFBSSxFQUFFLFFBQVE7WUFDZCxTQUFTLEVBQUUsS0FBSztTQUNqQixDQUFDLENBQ0gsQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUE7SUFDckIsQ0FBQyxDQUFDLENBQUE7SUFFRixFQUFFLENBQUMsdUVBQXVFLEVBQUUsS0FBSyxJQUFJLEVBQUU7UUFDckYsTUFBTSxxQkFBcUIsQ0FBQyxXQUFXLEVBQUUsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQTtRQUU1RCxNQUFNLE1BQU0sQ0FDVixxQkFBcUIsQ0FBQyxXQUFXLEVBQUUsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FDdkQsQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUE7SUFDckIsQ0FBQyxDQUFDLENBQUE7SUFFRixFQUFFLENBQUMsdURBQXVELEVBQUUsS0FBSyxJQUFJLEVBQUU7UUFDckUsTUFBTSxjQUFjLEdBQVk7WUFDOUIsSUFBSSxFQUFFLFNBQVM7WUFDZixTQUFTLEVBQUU7Z0JBQ1Q7b0JBQ0UsSUFBSSxFQUFFLFdBQVc7b0JBQ2pCLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxXQUFXLENBQUM7aUJBQ3RDO2FBQ0Y7U0FDRixDQUFBO1FBRUQsTUFBTSxjQUFjLEdBQVk7WUFDOUIsSUFBSSxFQUFFLFNBQVM7WUFDZixTQUFTLEVBQUU7Z0JBQ1Q7b0JBQ0UsSUFBSSxFQUFFLFdBQVc7b0JBQ2pCLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxXQUFXLENBQUM7aUJBQ3RDO2FBQ0Y7WUFDRCxXQUFXLEVBQUUsaUJBQWlCO1NBQy9CLENBQUE7UUFFRCxNQUFNLHFCQUFxQixDQUFDLGNBQWMsRUFBRSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFBO1FBRS9ELE1BQU0sY0FBYyxHQUFHLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsT0FBTyxDQUFDLENBQUE7UUFDM0QsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUMsQ0FBQTtRQUNoRCxNQUFNLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQTtRQUUxQyxNQUFNLHFCQUFxQixDQUFDLGNBQWMsRUFBRTtZQUMxQyxJQUFJLEVBQUUsUUFBUTtZQUNkLFNBQVMsRUFBRSxJQUFJO1NBQ2hCLENBQUMsQ0FBQTtRQUVGLE1BQU0sY0FBYyxHQUFHLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsT0FBTyxDQUFDLENBQUE7UUFDM0QsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUMsQ0FBQTtRQUNoRCxNQUFNLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQTtRQUMxQyxNQUFNLENBQUMsYUFBYSxDQUFDLFdBQVcsQ0FBQyxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFBO0lBQzNELENBQUMsQ0FBQyxDQUFBO0lBRUYsRUFBRSxDQUFDLDhDQUE4QyxFQUFFLEtBQUssSUFBSSxFQUFFO1FBQzVELE1BQU0sV0FBVyxHQUFZO1lBQzNCLElBQUksRUFBRSxjQUFjO1lBQ3BCLEtBQUssRUFBRSxjQUFjO1lBQ3JCLFdBQVcsRUFBRSwyQkFBMkI7WUFDeEMsT0FBTyxFQUFFLE9BQU87WUFDaEIsUUFBUSxFQUFFLHFCQUFxQjtZQUMvQixRQUFRLEVBQUUsQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLFNBQVMsQ0FBQztZQUNyQyxPQUFPLEVBQUUsc0JBQXNCO1lBQy9CLEtBQUssRUFBRSwrQkFBK0I7WUFDdEMsU0FBUyxFQUFFO2dCQUNUO29CQUNFLElBQUksRUFBRSxlQUFlO29CQUNyQixJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsVUFBVSxDQUFDO2lCQUNyQzthQUNGO1NBQ0YsQ0FBQTtRQUVELE1BQU0scUJBQXFCLENBQUMsV0FBVyxFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUE7UUFFNUQsTUFBTSxPQUFPLEdBQUcsTUFBTSxFQUFFLENBQUMsUUFBUSxDQUFDLFFBQVEsRUFBRSxPQUFPLENBQUMsQ0FBQTtRQUNwRCxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFBO1FBQ3pDLE1BQU0sQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUNqRCxNQUFNLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLENBQUE7UUFDbkQsTUFBTSxDQUFDLGFBQWEsQ0FBQyxXQUFXLENBQUMsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLFdBQVcsQ0FBQyxDQUFBO1FBQy9ELE1BQU0sQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsQ0FBQTtRQUN2RCxNQUFNLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLENBQUE7UUFDekQsTUFBTSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQyxDQUFBO1FBQzVELE1BQU0sQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsQ0FBQTtRQUN2RCxNQUFNLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLENBQUE7SUFDckQsQ0FBQyxDQUFDLENBQUE7SUFFRixFQUFFLENBQUMsdUNBQXVDLEVBQUUsS0FBSyxJQUFJLEVBQUU7UUFDckQsTUFBTSx1QkFBdUIsR0FBWTtZQUN2QyxJQUFJLEVBQUUsY0FBYztZQUNwQixTQUFTLEVBQUU7Z0JBQ1Q7b0JBQ0UsSUFBSSxFQUFFLGVBQWU7b0JBQ3JCLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxVQUFVLENBQUM7aUJBQ3JDO2FBQ0Y7WUFDRCxZQUFZLEVBQUU7Z0JBQ1o7b0JBQ0UsS0FBSyxFQUFFLFVBQVU7b0JBQ2pCLEtBQUssRUFBRSxrQkFBa0I7b0JBQ3pCLElBQUksRUFBRSxRQUFRO2lCQUNmO2dCQUNEO29CQUNFLEtBQUssRUFBRSxZQUFZO29CQUNuQixJQUFJLEVBQUUscUJBQXFCO2lCQUM1QjthQUNGO1NBQ0YsQ0FBQTtRQUVELE1BQU0scUJBQXFCLENBQUMsdUJBQXVCLEVBQUUsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQTtRQUV4RSxNQUFNLE9BQU8sR0FBRyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFBO1FBQ3BELE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUE7UUFDekMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxZQUFZLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUE7UUFDbEQsTUFBTSxDQUFDLGFBQWEsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFBO1FBQzdELE1BQU0sQ0FBQyxhQUFhLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQTtJQUNqRSxDQUFDLENBQUMsQ0FBQTtJQUVGLEVBQUUsQ0FBQyxtQ0FBbUMsRUFBRSxLQUFLLElBQUksRUFBRTtRQUNqRCxNQUFNLG1CQUFtQixHQUFZO1lBQ25DLElBQUksRUFBRSxjQUFjO1lBQ3BCLFNBQVMsRUFBRTtnQkFDVDtvQkFDRSxJQUFJLEVBQUUsZUFBZTtvQkFDckIsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLFVBQVUsQ0FBQztpQkFDckM7YUFDRjtZQUNELFFBQVEsRUFBRTtnQkFDUjtvQkFDRSxJQUFJLEVBQUUsS0FBSztvQkFDWCxJQUFJLEVBQUUscUNBQXFDO2lCQUM1QzthQUNGO1NBQ0YsQ0FBQTtRQUVELE1BQU0scUJBQXFCLENBQUMsbUJBQW1CLEVBQUUsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQTtRQUVwRSxNQUFNLE9BQU8sR0FBRyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFBO1FBQ3BELE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUE7UUFDekMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUE7UUFDOUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFBO0lBQ3JELENBQUMsQ0FBQyxDQUFBO0lBRUYsRUFBRSxDQUFDLGtDQUFrQyxFQUFFLEtBQUssSUFBSSxFQUFFO1FBQ2hELE1BQU0sa0JBQWtCLEdBQVk7WUFDbEMsSUFBSSxFQUFFLGNBQWM7WUFDcEIsU0FBUyxFQUFFO2dCQUNUO29CQUNFLElBQUksRUFBRSxlQUFlO29CQUNyQixJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsVUFBVSxDQUFDO2lCQUNyQzthQUNGO1lBQ0QsT0FBTyxFQUFFO2dCQUNQO29CQUNFLEtBQUssRUFBRSxnQkFBZ0I7b0JBQ3ZCLElBQUksRUFBRSwwQkFBMEI7aUJBQ2pDO2FBQ0Y7U0FDRixDQUFBO1FBRUQsTUFBTSxxQkFBcUIsQ0FBQyxrQkFBa0IsRUFBRSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFBO1FBRW5FLE1BQU0sT0FBTyxHQUFHLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsT0FBTyxDQUFDLENBQUE7UUFDcEQsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQTtRQUN6QyxNQUFNLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQTtRQUM3QyxNQUFNLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsQ0FBQTtJQUNoRSxDQUFDLENBQUMsQ0FBQTtBQUNKLENBQUMsQ0FBQyxDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgZnMgZnJvbSBcIm5vZGU6ZnMvcHJvbWlzZXNcIlxuaW1wb3J0ICogYXMgcGF0aCBmcm9tIFwibm9kZTpwYXRoXCJcbmltcG9ydCB7IHRlbXBvcmFyeURpcmVjdG9yeSB9IGZyb20gXCJ0ZW1weVwiXG5pbXBvcnQgeyBhZnRlckVhY2gsIGJlZm9yZUVhY2gsIGRlc2NyaWJlLCBleHBlY3QsIGl0IH0gZnJvbSBcInZpdGVzdFwiXG5pbXBvcnQgdHlwZSB7IFBhY2thZ2UgfSBmcm9tIFwiLi9QYWNrYWdlLnRzXCJcbmltcG9ydCB7IHNhdmVQYWNrYWdlRGVzY3JpcHRvciB9IGZyb20gXCIuL3NhdmUudHNcIlxuXG5kZXNjcmliZShcInNhdmVQYWNrYWdlRGVzY3JpcHRvclwiLCAoKSA9PiB7XG4gIGxldCB0ZXN0RGlyOiBzdHJpbmdcbiAgbGV0IHRlc3RQYXRoOiBzdHJpbmdcbiAgbGV0IHRlc3RQYWNrYWdlOiBQYWNrYWdlXG5cbiAgYmVmb3JlRWFjaCgoKSA9PiB7XG4gICAgdGVzdERpciA9IHRlbXBvcmFyeURpcmVjdG9yeSgpXG4gICAgdGVzdFBhdGggPSBwYXRoLmpvaW4odGVzdERpciwgXCJkYXRhcGFja2FnZS5qc29uXCIpXG4gICAgdGVzdFBhY2thZ2UgPSB7XG4gICAgICBuYW1lOiBcInRlc3QtcGFja2FnZVwiLFxuICAgICAgcmVzb3VyY2VzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBuYW1lOiBcInRlc3QtcmVzb3VyY2VcIixcbiAgICAgICAgICBwYXRoOiBwYXRoLmpvaW4odGVzdERpciwgXCJkYXRhLmNzdlwiKSxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfVxuICB9KVxuXG4gIGFmdGVyRWFjaChhc3luYyAoKSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGZzLnJtKHRlc3REaXIsIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvciAmJiAhZXJyb3IubWVzc2FnZS5pbmNsdWRlcyhcIkVOT0VOVFwiKSkge1xuICAgICAgICBjb25zb2xlLmVycm9yKGBGYWlsZWQgdG8gY2xlYW4gdXAgdGVzdCBkaXJlY3Rvcnk6ICR7dGVzdERpcn1gLCBlcnJvcilcbiAgICAgIH1cbiAgICB9XG4gIH0pXG5cbiAgaXQoXCJzaG91bGQgc2F2ZSBhIHBhY2thZ2UgZGVzY3JpcHRvciB0byBhIGZpbGUgYW5kIG1haW50YWluIGl0cyBzdHJ1Y3R1cmVcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGF3YWl0IHNhdmVQYWNrYWdlRGVzY3JpcHRvcih0ZXN0UGFja2FnZSwgeyBwYXRoOiB0ZXN0UGF0aCB9KVxuXG4gICAgY29uc3QgZmlsZUV4aXN0cyA9IGF3YWl0IGZzXG4gICAgICAuc3RhdCh0ZXN0UGF0aClcbiAgICAgIC50aGVuKCgpID0+IHRydWUpXG4gICAgICAuY2F0Y2goKCkgPT4gZmFsc2UpXG4gICAgZXhwZWN0KGZpbGVFeGlzdHMpLnRvQmUodHJ1ZSlcblxuICAgIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCBmcy5yZWFkRmlsZSh0ZXN0UGF0aCwgXCJ1dGYtOFwiKVxuICAgIGNvbnN0IHBhcnNlZENvbnRlbnQgPSBKU09OLnBhcnNlKGNvbnRlbnQpXG5cbiAgICBjb25zdCB7ICRzY2hlbWEsIC4uLnBhY2thZ2VXaXRob3V0U2NoZW1hIH0gPSBwYXJzZWRDb250ZW50XG4gICAgZXhwZWN0KHBhY2thZ2VXaXRob3V0U2NoZW1hLm5hbWUpLnRvRXF1YWwodGVzdFBhY2thZ2UubmFtZSlcbiAgICBleHBlY3QocGFja2FnZVdpdGhvdXRTY2hlbWEucmVzb3VyY2VzKS50b0hhdmVMZW5ndGgoMSlcbiAgICBleHBlY3QocGFja2FnZVdpdGhvdXRTY2hlbWEucmVzb3VyY2VzWzBdLm5hbWUpLnRvQmUoXCJ0ZXN0LXJlc291cmNlXCIpXG4gICAgZXhwZWN0KHBhY2thZ2VXaXRob3V0U2NoZW1hLnJlc291cmNlc1swXS5wYXRoKS50b0JlKFwiZGF0YS5jc3ZcIilcbiAgICBleHBlY3QoJHNjaGVtYSkudG9CZShcbiAgICAgIFwiaHR0cHM6Ly9kYXRhcGFja2FnZS5vcmcvcHJvZmlsZXMvMi4wL2RhdGFwYWNrYWdlLmpzb25cIixcbiAgICApXG4gIH0pXG5cbiAgaXQoXCJzaG91bGQgYWRkICRzY2hlbWEgcHJvcGVydHkgaWYgbm90IHByZXNlbnRcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGF3YWl0IHNhdmVQYWNrYWdlRGVzY3JpcHRvcih0ZXN0UGFja2FnZSwgeyBwYXRoOiB0ZXN0UGF0aCB9KVxuXG4gICAgY29uc3QgY29udGVudCA9IGF3YWl0IGZzLnJlYWRGaWxlKHRlc3RQYXRoLCBcInV0Zi04XCIpXG4gICAgY29uc3QgcGFyc2VkQ29udGVudCA9IEpTT04ucGFyc2UoY29udGVudClcbiAgICBleHBlY3QocGFyc2VkQ29udGVudC4kc2NoZW1hKS50b0JlKFxuICAgICAgXCJodHRwczovL2RhdGFwYWNrYWdlLm9yZy9wcm9maWxlcy8yLjAvZGF0YXBhY2thZ2UuanNvblwiLFxuICAgIClcbiAgfSlcblxuICBpdChcInNob3VsZCBwcmVzZXJ2ZSBleGlzdGluZyAkc2NoZW1hIHByb3BlcnR5XCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBwYWNrYWdlV2l0aFNjaGVtYTogUGFja2FnZSA9IHtcbiAgICAgIG5hbWU6IFwidGVzdC1wYWNrYWdlXCIsXG4gICAgICByZXNvdXJjZXM6IFtcbiAgICAgICAge1xuICAgICAgICAgIG5hbWU6IFwidGVzdC1yZXNvdXJjZVwiLFxuICAgICAgICAgIHBhdGg6IHBhdGguam9pbih0ZXN0RGlyLCBcImRhdGEuY3N2XCIpLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICAgICRzY2hlbWE6IFwiaHR0cHM6Ly9jdXN0b20uc2NoZW1hLnVybFwiLFxuICAgIH1cblxuICAgIGF3YWl0IHNhdmVQYWNrYWdlRGVzY3JpcHRvcihwYWNrYWdlV2l0aFNjaGVtYSwgeyBwYXRoOiB0ZXN0UGF0aCB9KVxuXG4gICAgY29uc3QgY29udGVudCA9IGF3YWl0IGZzLnJlYWRGaWxlKHRlc3RQYXRoLCBcInV0Zi04XCIpXG4gICAgY29uc3QgcGFyc2VkQ29udGVudCA9IEpTT04ucGFyc2UoY29udGVudClcbiAgICBleHBlY3QocGFyc2VkQ29udGVudC4kc2NoZW1hKS50b0JlKFwiaHR0cHM6Ly9jdXN0b20uc2NoZW1hLnVybFwiKVxuICB9KVxuXG4gIGl0KFwic2hvdWxkIHVzZSBwcmV0dHkgZm9ybWF0dGluZyB3aXRoIDItc3BhY2UgaW5kZW50YXRpb25cIiwgYXN5bmMgKCkgPT4ge1xuICAgIGF3YWl0IHNhdmVQYWNrYWdlRGVzY3JpcHRvcih0ZXN0UGFja2FnZSwgeyBwYXRoOiB0ZXN0UGF0aCB9KVxuXG4gICAgY29uc3QgY29udGVudCA9IGF3YWl0IGZzLnJlYWRGaWxlKHRlc3RQYXRoLCBcInV0Zi04XCIpXG4gICAgY29uc3QgbGluZXMgPSBjb250ZW50LnNwbGl0KFwiXFxuXCIpXG4gICAgZXhwZWN0KGxpbmVzLmxlbmd0aCkudG9CZUdyZWF0ZXJUaGFuKDEpXG5cbiAgICBpZiAobGluZXMubGVuZ3RoID4gMSAmJiBsaW5lc1sxXSkge1xuICAgICAgZXhwZWN0KGxpbmVzWzFdLnN0YXJ0c1dpdGgoXCIgIFwiKSkudG9CZSh0cnVlKVxuICAgIH1cbiAgfSlcblxuICBpdChcInNob3VsZCBzYXZlIHBhY2thZ2Ugd2l0aCBtdWx0aXBsZSByZXNvdXJjZXNcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IHBhY2thZ2VXaXRoTXVsdGlwbGVSZXNvdXJjZXM6IFBhY2thZ2UgPSB7XG4gICAgICBuYW1lOiBcInRlc3QtcGFja2FnZVwiLFxuICAgICAgcmVzb3VyY2VzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBuYW1lOiBcInJlc291cmNlMVwiLFxuICAgICAgICAgIHBhdGg6IHBhdGguam9pbih0ZXN0RGlyLCBcImRhdGExLmNzdlwiKSxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIG5hbWU6IFwicmVzb3VyY2UyXCIsXG4gICAgICAgICAgcGF0aDogcGF0aC5qb2luKHRlc3REaXIsIFwiZGF0YTIuanNvblwiKSxcbiAgICAgICAgICBmb3JtYXQ6IFwianNvblwiLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9XG5cbiAgICBhd2FpdCBzYXZlUGFja2FnZURlc2NyaXB0b3IocGFja2FnZVdpdGhNdWx0aXBsZVJlc291cmNlcywge1xuICAgICAgcGF0aDogdGVzdFBhdGgsXG4gICAgfSlcblxuICAgIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCBmcy5yZWFkRmlsZSh0ZXN0UGF0aCwgXCJ1dGYtOFwiKVxuICAgIGNvbnN0IHBhcnNlZENvbnRlbnQgPSBKU09OLnBhcnNlKGNvbnRlbnQpXG4gICAgZXhwZWN0KHBhcnNlZENvbnRlbnQucmVzb3VyY2VzKS50b0hhdmVMZW5ndGgoMilcbiAgICBleHBlY3QocGFyc2VkQ29udGVudC5yZXNvdXJjZXNbMF0/Lm5hbWUpLnRvQmUoXCJyZXNvdXJjZTFcIilcbiAgICBleHBlY3QocGFyc2VkQ29udGVudC5yZXNvdXJjZXNbMV0/Lm5hbWUpLnRvQmUoXCJyZXNvdXJjZTJcIilcbiAgfSlcblxuICBpdChcInNob3VsZCBzYXZlIHBhY2thZ2Ugd2l0aCByZXNvdXJjZSBjb250YWluaW5nIHNjaGVtYVwiLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgcGFja2FnZVdpdGhTY2hlbWE6IFBhY2thZ2UgPSB7XG4gICAgICBuYW1lOiBcInRlc3QtcGFja2FnZVwiLFxuICAgICAgcmVzb3VyY2VzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBuYW1lOiBcInRlc3QtcmVzb3VyY2VcIixcbiAgICAgICAgICBwYXRoOiBwYXRoLmpvaW4odGVzdERpciwgXCJkYXRhLmNzdlwiKSxcbiAgICAgICAgICBzY2hlbWE6IHtcbiAgICAgICAgICAgIGZpZWxkczogW1xuICAgICAgICAgICAgICB7IG5hbWU6IFwiaWRcIiwgdHlwZTogXCJpbnRlZ2VyXCIgfSxcbiAgICAgICAgICAgICAgeyBuYW1lOiBcIm5hbWVcIiwgdHlwZTogXCJzdHJpbmdcIiB9LFxuICAgICAgICAgICAgXSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9XG5cbiAgICBhd2FpdCBzYXZlUGFja2FnZURlc2NyaXB0b3IocGFja2FnZVdpdGhTY2hlbWEsIHsgcGF0aDogdGVzdFBhdGggfSlcblxuICAgIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCBmcy5yZWFkRmlsZSh0ZXN0UGF0aCwgXCJ1dGYtOFwiKVxuICAgIGNvbnN0IHBhcnNlZENvbnRlbnQgPSBKU09OLnBhcnNlKGNvbnRlbnQpXG4gICAgZXhwZWN0KHBhcnNlZENvbnRlbnQucmVzb3VyY2VzWzBdPy5zY2hlbWEpLnRvRXF1YWwoXG4gICAgICBwYWNrYWdlV2l0aFNjaGVtYS5yZXNvdXJjZXNbMF0/LnNjaGVtYSxcbiAgICApXG4gIH0pXG5cbiAgaXQoXCJzaG91bGQgc2F2ZSBwYWNrYWdlIHdpdGggcmVzb3VyY2UgY29udGFpbmluZyBkaWFsZWN0XCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBwYWNrYWdlV2l0aERpYWxlY3Q6IFBhY2thZ2UgPSB7XG4gICAgICBuYW1lOiBcInRlc3QtcGFja2FnZVwiLFxuICAgICAgcmVzb3VyY2VzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBuYW1lOiBcInRlc3QtcmVzb3VyY2VcIixcbiAgICAgICAgICBwYXRoOiBwYXRoLmpvaW4odGVzdERpciwgXCJkYXRhLmNzdlwiKSxcbiAgICAgICAgICBkaWFsZWN0OiB7XG4gICAgICAgICAgICBkZWxpbWl0ZXI6IFwiO1wiLFxuICAgICAgICAgICAgbGluZVRlcm1pbmF0b3I6IFwiXFxuXCIsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfVxuXG4gICAgYXdhaXQgc2F2ZVBhY2thZ2VEZXNjcmlwdG9yKHBhY2thZ2VXaXRoRGlhbGVjdCwgeyBwYXRoOiB0ZXN0UGF0aCB9KVxuXG4gICAgY29uc3QgY29udGVudCA9IGF3YWl0IGZzLnJlYWRGaWxlKHRlc3RQYXRoLCBcInV0Zi04XCIpXG4gICAgY29uc3QgcGFyc2VkQ29udGVudCA9IEpTT04ucGFyc2UoY29udGVudClcbiAgICBleHBlY3QocGFyc2VkQ29udGVudC5yZXNvdXJjZXNbMF0/LmRpYWxlY3QpLnRvRXF1YWwoXG4gICAgICBwYWNrYWdlV2l0aERpYWxlY3QucmVzb3VyY2VzWzBdPy5kaWFsZWN0LFxuICAgIClcbiAgfSlcblxuICBpdChcInNob3VsZCBzYXZlIHBhY2thZ2UgdG8gYSBuZXN0ZWQgZGlyZWN0b3J5IHBhdGhcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IG5lc3RlZFBhdGggPSBwYXRoLmpvaW4odGVzdERpciwgXCJuZXN0ZWRcIiwgXCJkaXJcIiwgXCJkYXRhcGFja2FnZS5qc29uXCIpXG4gICAgY29uc3QgbmVzdGVkUGFja2FnZTogUGFja2FnZSA9IHtcbiAgICAgIG5hbWU6IFwidGVzdC1wYWNrYWdlXCIsXG4gICAgICByZXNvdXJjZXM6IFtcbiAgICAgICAge1xuICAgICAgICAgIG5hbWU6IFwidGVzdC1yZXNvdXJjZVwiLFxuICAgICAgICAgIHBhdGg6IHBhdGguam9pbih0ZXN0RGlyLCBcIm5lc3RlZFwiLCBcImRpclwiLCBcImRhdGEuY3N2XCIpLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9XG5cbiAgICBhd2FpdCBzYXZlUGFja2FnZURlc2NyaXB0b3IobmVzdGVkUGFja2FnZSwgeyBwYXRoOiBuZXN0ZWRQYXRoIH0pXG5cbiAgICBjb25zdCBmaWxlRXhpc3RzID0gYXdhaXQgZnNcbiAgICAgIC5zdGF0KG5lc3RlZFBhdGgpXG4gICAgICAudGhlbigoKSA9PiB0cnVlKVxuICAgICAgLmNhdGNoKCgpID0+IGZhbHNlKVxuICAgIGV4cGVjdChmaWxlRXhpc3RzKS50b0JlKHRydWUpXG5cbiAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgZnMucmVhZEZpbGUobmVzdGVkUGF0aCwgXCJ1dGYtOFwiKVxuICAgIGNvbnN0IHBhcnNlZENvbnRlbnQgPSBKU09OLnBhcnNlKGNvbnRlbnQpXG4gICAgZXhwZWN0KHBhcnNlZENvbnRlbnQubmFtZSkudG9CZShuZXN0ZWRQYWNrYWdlLm5hbWUpXG4gIH0pXG5cbiAgaXQoXCJzaG91bGQgdGhyb3cgYW4gZXJyb3Igd2hlbiBmaWxlIGV4aXN0cyBhbmQgb3ZlcndyaXRlIGlzIGZhbHNlXCIsIGFzeW5jICgpID0+IHtcbiAgICBhd2FpdCBzYXZlUGFja2FnZURlc2NyaXB0b3IodGVzdFBhY2thZ2UsIHsgcGF0aDogdGVzdFBhdGggfSlcblxuICAgIGF3YWl0IGV4cGVjdChcbiAgICAgIHNhdmVQYWNrYWdlRGVzY3JpcHRvcih0ZXN0UGFja2FnZSwge1xuICAgICAgICBwYXRoOiB0ZXN0UGF0aCxcbiAgICAgICAgb3ZlcndyaXRlOiBmYWxzZSxcbiAgICAgIH0pLFxuICAgICkucmVqZWN0cy50b1Rocm93KClcbiAgfSlcblxuICBpdChcInNob3VsZCB0aHJvdyBhbiBlcnJvciB3aGVuIGZpbGUgZXhpc3RzIGFuZCBvdmVyd3JpdGUgaXMgbm90IHNwZWNpZmllZFwiLCBhc3luYyAoKSA9PiB7XG4gICAgYXdhaXQgc2F2ZVBhY2thZ2VEZXNjcmlwdG9yKHRlc3RQYWNrYWdlLCB7IHBhdGg6IHRlc3RQYXRoIH0pXG5cbiAgICBhd2FpdCBleHBlY3QoXG4gICAgICBzYXZlUGFja2FnZURlc2NyaXB0b3IodGVzdFBhY2thZ2UsIHsgcGF0aDogdGVzdFBhdGggfSksXG4gICAgKS5yZWplY3RzLnRvVGhyb3coKVxuICB9KVxuXG4gIGl0KFwic2hvdWxkIG92ZXJ3cml0ZSBleGlzdGluZyBmaWxlIHdoZW4gb3ZlcndyaXRlIGlzIHRydWVcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGluaXRpYWxQYWNrYWdlOiBQYWNrYWdlID0ge1xuICAgICAgbmFtZTogXCJpbml0aWFsXCIsXG4gICAgICByZXNvdXJjZXM6IFtcbiAgICAgICAge1xuICAgICAgICAgIG5hbWU6IFwicmVzb3VyY2UxXCIsXG4gICAgICAgICAgcGF0aDogcGF0aC5qb2luKHRlc3REaXIsIFwiZGF0YTEuY3N2XCIpLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9XG5cbiAgICBjb25zdCB1cGRhdGVkUGFja2FnZTogUGFja2FnZSA9IHtcbiAgICAgIG5hbWU6IFwidXBkYXRlZFwiLFxuICAgICAgcmVzb3VyY2VzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBuYW1lOiBcInJlc291cmNlMlwiLFxuICAgICAgICAgIHBhdGg6IHBhdGguam9pbih0ZXN0RGlyLCBcImRhdGEyLmNzdlwiKSxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgICBkZXNjcmlwdGlvbjogXCJVcGRhdGVkIHBhY2thZ2VcIixcbiAgICB9XG5cbiAgICBhd2FpdCBzYXZlUGFja2FnZURlc2NyaXB0b3IoaW5pdGlhbFBhY2thZ2UsIHsgcGF0aDogdGVzdFBhdGggfSlcblxuICAgIGNvbnN0IGluaXRpYWxDb250ZW50ID0gYXdhaXQgZnMucmVhZEZpbGUodGVzdFBhdGgsIFwidXRmLThcIilcbiAgICBjb25zdCBpbml0aWFsUGFyc2VkID0gSlNPTi5wYXJzZShpbml0aWFsQ29udGVudClcbiAgICBleHBlY3QoaW5pdGlhbFBhcnNlZC5uYW1lKS50b0JlKFwiaW5pdGlhbFwiKVxuXG4gICAgYXdhaXQgc2F2ZVBhY2thZ2VEZXNjcmlwdG9yKHVwZGF0ZWRQYWNrYWdlLCB7XG4gICAgICBwYXRoOiB0ZXN0UGF0aCxcbiAgICAgIG92ZXJ3cml0ZTogdHJ1ZSxcbiAgICB9KVxuXG4gICAgY29uc3QgdXBkYXRlZENvbnRlbnQgPSBhd2FpdCBmcy5yZWFkRmlsZSh0ZXN0UGF0aCwgXCJ1dGYtOFwiKVxuICAgIGNvbnN0IHVwZGF0ZWRQYXJzZWQgPSBKU09OLnBhcnNlKHVwZGF0ZWRDb250ZW50KVxuICAgIGV4cGVjdCh1cGRhdGVkUGFyc2VkLm5hbWUpLnRvQmUoXCJ1cGRhdGVkXCIpXG4gICAgZXhwZWN0KHVwZGF0ZWRQYXJzZWQuZGVzY3JpcHRpb24pLnRvQmUoXCJVcGRhdGVkIHBhY2thZ2VcIilcbiAgfSlcblxuICBpdChcInNob3VsZCBzYXZlIHBhY2thZ2Ugd2l0aCBhbGwgbWV0YWRhdGEgZmllbGRzXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBmdWxsUGFja2FnZTogUGFja2FnZSA9IHtcbiAgICAgIG5hbWU6IFwiZnVsbC1wYWNrYWdlXCIsXG4gICAgICB0aXRsZTogXCJGdWxsIFBhY2thZ2VcIixcbiAgICAgIGRlc2NyaXB0aW9uOiBcIkEgcGFja2FnZSB3aXRoIGFsbCBmaWVsZHNcIixcbiAgICAgIHZlcnNpb246IFwiMS4wLjBcIixcbiAgICAgIGhvbWVwYWdlOiBcImh0dHBzOi8vZXhhbXBsZS5jb21cIixcbiAgICAgIGtleXdvcmRzOiBbXCJ0ZXN0XCIsIFwiZGF0YVwiLCBcInBhY2thZ2VcIl0sXG4gICAgICBjcmVhdGVkOiBcIjIwMjQtMDEtMDFUMDA6MDA6MDBaXCIsXG4gICAgICBpbWFnZTogXCJodHRwczovL2V4YW1wbGUuY29tL2ltYWdlLnBuZ1wiLFxuICAgICAgcmVzb3VyY2VzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBuYW1lOiBcInRlc3QtcmVzb3VyY2VcIixcbiAgICAgICAgICBwYXRoOiBwYXRoLmpvaW4odGVzdERpciwgXCJkYXRhLmNzdlwiKSxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfVxuXG4gICAgYXdhaXQgc2F2ZVBhY2thZ2VEZXNjcmlwdG9yKGZ1bGxQYWNrYWdlLCB7IHBhdGg6IHRlc3RQYXRoIH0pXG5cbiAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgZnMucmVhZEZpbGUodGVzdFBhdGgsIFwidXRmLThcIilcbiAgICBjb25zdCBwYXJzZWRDb250ZW50ID0gSlNPTi5wYXJzZShjb250ZW50KVxuICAgIGV4cGVjdChwYXJzZWRDb250ZW50Lm5hbWUpLnRvQmUoZnVsbFBhY2thZ2UubmFtZSlcbiAgICBleHBlY3QocGFyc2VkQ29udGVudC50aXRsZSkudG9CZShmdWxsUGFja2FnZS50aXRsZSlcbiAgICBleHBlY3QocGFyc2VkQ29udGVudC5kZXNjcmlwdGlvbikudG9CZShmdWxsUGFja2FnZS5kZXNjcmlwdGlvbilcbiAgICBleHBlY3QocGFyc2VkQ29udGVudC52ZXJzaW9uKS50b0JlKGZ1bGxQYWNrYWdlLnZlcnNpb24pXG4gICAgZXhwZWN0KHBhcnNlZENvbnRlbnQuaG9tZXBhZ2UpLnRvQmUoZnVsbFBhY2thZ2UuaG9tZXBhZ2UpXG4gICAgZXhwZWN0KHBhcnNlZENvbnRlbnQua2V5d29yZHMpLnRvRXF1YWwoZnVsbFBhY2thZ2Uua2V5d29yZHMpXG4gICAgZXhwZWN0KHBhcnNlZENvbnRlbnQuY3JlYXRlZCkudG9CZShmdWxsUGFja2FnZS5jcmVhdGVkKVxuICAgIGV4cGVjdChwYXJzZWRDb250ZW50LmltYWdlKS50b0JlKGZ1bGxQYWNrYWdlLmltYWdlKVxuICB9KVxuXG4gIGl0KFwic2hvdWxkIHNhdmUgcGFja2FnZSB3aXRoIGNvbnRyaWJ1dG9yc1wiLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgcGFja2FnZVdpdGhDb250cmlidXRvcnM6IFBhY2thZ2UgPSB7XG4gICAgICBuYW1lOiBcInRlc3QtcGFja2FnZVwiLFxuICAgICAgcmVzb3VyY2VzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBuYW1lOiBcInRlc3QtcmVzb3VyY2VcIixcbiAgICAgICAgICBwYXRoOiBwYXRoLmpvaW4odGVzdERpciwgXCJkYXRhLmNzdlwiKSxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgICBjb250cmlidXRvcnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIHRpdGxlOiBcIkpvaG4gRG9lXCIsXG4gICAgICAgICAgZW1haWw6IFwiam9obkBleGFtcGxlLmNvbVwiLFxuICAgICAgICAgIHJvbGU6IFwiYXV0aG9yXCIsXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICB0aXRsZTogXCJKYW5lIFNtaXRoXCIsXG4gICAgICAgICAgcGF0aDogXCJodHRwczovL2V4YW1wbGUub3JnXCIsXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH1cblxuICAgIGF3YWl0IHNhdmVQYWNrYWdlRGVzY3JpcHRvcihwYWNrYWdlV2l0aENvbnRyaWJ1dG9ycywgeyBwYXRoOiB0ZXN0UGF0aCB9KVxuXG4gICAgY29uc3QgY29udGVudCA9IGF3YWl0IGZzLnJlYWRGaWxlKHRlc3RQYXRoLCBcInV0Zi04XCIpXG4gICAgY29uc3QgcGFyc2VkQ29udGVudCA9IEpTT04ucGFyc2UoY29udGVudClcbiAgICBleHBlY3QocGFyc2VkQ29udGVudC5jb250cmlidXRvcnMpLnRvSGF2ZUxlbmd0aCgyKVxuICAgIGV4cGVjdChwYXJzZWRDb250ZW50LmNvbnRyaWJ1dG9yc1swXT8udGl0bGUpLnRvQmUoXCJKb2huIERvZVwiKVxuICAgIGV4cGVjdChwYXJzZWRDb250ZW50LmNvbnRyaWJ1dG9yc1sxXT8udGl0bGUpLnRvQmUoXCJKYW5lIFNtaXRoXCIpXG4gIH0pXG5cbiAgaXQoXCJzaG91bGQgc2F2ZSBwYWNrYWdlIHdpdGggbGljZW5zZXNcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IHBhY2thZ2VXaXRoTGljZW5zZXM6IFBhY2thZ2UgPSB7XG4gICAgICBuYW1lOiBcInRlc3QtcGFja2FnZVwiLFxuICAgICAgcmVzb3VyY2VzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBuYW1lOiBcInRlc3QtcmVzb3VyY2VcIixcbiAgICAgICAgICBwYXRoOiBwYXRoLmpvaW4odGVzdERpciwgXCJkYXRhLmNzdlwiKSxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgICBsaWNlbnNlczogW1xuICAgICAgICB7XG4gICAgICAgICAgbmFtZTogXCJNSVRcIixcbiAgICAgICAgICBwYXRoOiBcImh0dHBzOi8vb3BlbnNvdXJjZS5vcmcvbGljZW5zZXMvTUlUXCIsXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH1cblxuICAgIGF3YWl0IHNhdmVQYWNrYWdlRGVzY3JpcHRvcihwYWNrYWdlV2l0aExpY2Vuc2VzLCB7IHBhdGg6IHRlc3RQYXRoIH0pXG5cbiAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgZnMucmVhZEZpbGUodGVzdFBhdGgsIFwidXRmLThcIilcbiAgICBjb25zdCBwYXJzZWRDb250ZW50ID0gSlNPTi5wYXJzZShjb250ZW50KVxuICAgIGV4cGVjdChwYXJzZWRDb250ZW50LmxpY2Vuc2VzKS50b0hhdmVMZW5ndGgoMSlcbiAgICBleHBlY3QocGFyc2VkQ29udGVudC5saWNlbnNlc1swXT8ubmFtZSkudG9CZShcIk1JVFwiKVxuICB9KVxuXG4gIGl0KFwic2hvdWxkIHNhdmUgcGFja2FnZSB3aXRoIHNvdXJjZXNcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IHBhY2thZ2VXaXRoU291cmNlczogUGFja2FnZSA9IHtcbiAgICAgIG5hbWU6IFwidGVzdC1wYWNrYWdlXCIsXG4gICAgICByZXNvdXJjZXM6IFtcbiAgICAgICAge1xuICAgICAgICAgIG5hbWU6IFwidGVzdC1yZXNvdXJjZVwiLFxuICAgICAgICAgIHBhdGg6IHBhdGguam9pbih0ZXN0RGlyLCBcImRhdGEuY3N2XCIpLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICAgIHNvdXJjZXM6IFtcbiAgICAgICAge1xuICAgICAgICAgIHRpdGxlOiBcIkV4YW1wbGUgU291cmNlXCIsXG4gICAgICAgICAgcGF0aDogXCJodHRwczovL2V4YW1wbGUuY29tL2RhdGFcIixcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfVxuXG4gICAgYXdhaXQgc2F2ZVBhY2thZ2VEZXNjcmlwdG9yKHBhY2thZ2VXaXRoU291cmNlcywgeyBwYXRoOiB0ZXN0UGF0aCB9KVxuXG4gICAgY29uc3QgY29udGVudCA9IGF3YWl0IGZzLnJlYWRGaWxlKHRlc3RQYXRoLCBcInV0Zi04XCIpXG4gICAgY29uc3QgcGFyc2VkQ29udGVudCA9IEpTT04ucGFyc2UoY29udGVudClcbiAgICBleHBlY3QocGFyc2VkQ29udGVudC5zb3VyY2VzKS50b0hhdmVMZW5ndGgoMSlcbiAgICBleHBlY3QocGFyc2VkQ29udGVudC5zb3VyY2VzWzBdPy50aXRsZSkudG9CZShcIkV4YW1wbGUgU291cmNlXCIpXG4gIH0pXG59KVxuIl19
@@ -0,0 +1,12 @@
1
+ import type { Descriptor } from "../descriptor/index.ts";
2
+ import type { Package } from "./Package.ts";
3
+ /**
4
+ * Validate a Package descriptor (JSON Object) against its profile
5
+ */
6
+ export declare function validatePackageMetadata(source: Package | Descriptor | string, options?: {
7
+ basepath?: string;
8
+ }): Promise<{
9
+ dataPackage: Package | undefined;
10
+ errors: import("../index.ts").MetadataError[];
11
+ valid: boolean;
12
+ }>;
@@ -0,0 +1,27 @@
1
+ import { loadDescriptor } from "../descriptor/index.js";
2
+ import { validateDescriptor } from "../profile/index.js";
3
+ import { convertPackageFromDescriptor } from "./convert/fromDescriptor.js";
4
+ const DEFAULT_PROFILE = "https://datapackage.org/profiles/1.0/datapackage.json";
5
+ /**
6
+ * Validate a Package descriptor (JSON Object) against its profile
7
+ */
8
+ export async function validatePackageMetadata(source, options) {
9
+ const descriptor = typeof source === "string"
10
+ ? await loadDescriptor(source)
11
+ : source;
12
+ const profile = typeof descriptor.$schema === "string"
13
+ ? descriptor.$schema
14
+ : DEFAULT_PROFILE;
15
+ const report = await validateDescriptor(descriptor, {
16
+ profile,
17
+ });
18
+ let dataPackage = undefined;
19
+ if (report.valid) {
20
+ // Validation + normalization = we can cast it
21
+ dataPackage = convertPackageFromDescriptor(descriptor, {
22
+ basepath: options?.basepath,
23
+ });
24
+ }
25
+ return { ...report, dataPackage };
26
+ }
27
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9wYWNrYWdlL3ZhbGlkYXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQTtBQUN2RCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQTtBQUV4RCxPQUFPLEVBQUUsNEJBQTRCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQTtBQUUxRSxNQUFNLGVBQWUsR0FBRyx1REFBdUQsQ0FBQTtBQUUvRTs7R0FFRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsdUJBQXVCLENBQzNDLE1BQXFDLEVBQ3JDLE9BRUM7SUFFRCxNQUFNLFVBQVUsR0FDZCxPQUFPLE1BQU0sS0FBSyxRQUFRO1FBQ3hCLENBQUMsQ0FBQyxNQUFNLGNBQWMsQ0FBQyxNQUFNLENBQUM7UUFDOUIsQ0FBQyxDQUFFLE1BQXFCLENBQUE7SUFFNUIsTUFBTSxPQUFPLEdBQ1gsT0FBTyxVQUFVLENBQUMsT0FBTyxLQUFLLFFBQVE7UUFDcEMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxPQUFPO1FBQ3BCLENBQUMsQ0FBQyxlQUFlLENBQUE7SUFFckIsTUFBTSxNQUFNLEdBQUcsTUFBTSxrQkFBa0IsQ0FBQyxVQUFVLEVBQUU7UUFDbEQsT0FBTztLQUNSLENBQUMsQ0FBQTtJQUVGLElBQUksV0FBVyxHQUF3QixTQUFTLENBQUE7SUFDaEQsSUFBSSxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDakIsOENBQThDO1FBQzlDLFdBQVcsR0FBRyw0QkFBNEIsQ0FBQyxVQUFVLEVBQUU7WUFDckQsUUFBUSxFQUFFLE9BQU8sRUFBRSxRQUFRO1NBQzVCLENBQXVCLENBQUE7SUFDMUIsQ0FBQztJQUVELE9BQU8sRUFBRSxHQUFHLE1BQU0sRUFBRSxXQUFXLEVBQUUsQ0FBQTtBQUNuQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBEZXNjcmlwdG9yIH0gZnJvbSBcIi4uL2Rlc2NyaXB0b3IvaW5kZXgudHNcIlxuaW1wb3J0IHsgbG9hZERlc2NyaXB0b3IgfSBmcm9tIFwiLi4vZGVzY3JpcHRvci9pbmRleC50c1wiXG5pbXBvcnQgeyB2YWxpZGF0ZURlc2NyaXB0b3IgfSBmcm9tIFwiLi4vcHJvZmlsZS9pbmRleC50c1wiXG5pbXBvcnQgdHlwZSB7IFBhY2thZ2UgfSBmcm9tIFwiLi9QYWNrYWdlLnRzXCJcbmltcG9ydCB7IGNvbnZlcnRQYWNrYWdlRnJvbURlc2NyaXB0b3IgfSBmcm9tIFwiLi9jb252ZXJ0L2Zyb21EZXNjcmlwdG9yLnRzXCJcblxuY29uc3QgREVGQVVMVF9QUk9GSUxFID0gXCJodHRwczovL2RhdGFwYWNrYWdlLm9yZy9wcm9maWxlcy8xLjAvZGF0YXBhY2thZ2UuanNvblwiXG5cbi8qKlxuICogVmFsaWRhdGUgYSBQYWNrYWdlIGRlc2NyaXB0b3IgKEpTT04gT2JqZWN0KSBhZ2FpbnN0IGl0cyBwcm9maWxlXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB2YWxpZGF0ZVBhY2thZ2VNZXRhZGF0YShcbiAgc291cmNlOiBQYWNrYWdlIHwgRGVzY3JpcHRvciB8IHN0cmluZyxcbiAgb3B0aW9ucz86IHtcbiAgICBiYXNlcGF0aD86IHN0cmluZ1xuICB9LFxuKSB7XG4gIGNvbnN0IGRlc2NyaXB0b3IgPVxuICAgIHR5cGVvZiBzb3VyY2UgPT09IFwic3RyaW5nXCJcbiAgICAgID8gYXdhaXQgbG9hZERlc2NyaXB0b3Ioc291cmNlKVxuICAgICAgOiAoc291cmNlIGFzIERlc2NyaXB0b3IpXG5cbiAgY29uc3QgcHJvZmlsZSA9XG4gICAgdHlwZW9mIGRlc2NyaXB0b3IuJHNjaGVtYSA9PT0gXCJzdHJpbmdcIlxuICAgICAgPyBkZXNjcmlwdG9yLiRzY2hlbWFcbiAgICAgIDogREVGQVVMVF9QUk9GSUxFXG5cbiAgY29uc3QgcmVwb3J0ID0gYXdhaXQgdmFsaWRhdGVEZXNjcmlwdG9yKGRlc2NyaXB0b3IsIHtcbiAgICBwcm9maWxlLFxuICB9KVxuXG4gIGxldCBkYXRhUGFja2FnZTogUGFja2FnZSB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZFxuICBpZiAocmVwb3J0LnZhbGlkKSB7XG4gICAgLy8gVmFsaWRhdGlvbiArIG5vcm1hbGl6YXRpb24gPSB3ZSBjYW4gY2FzdCBpdFxuICAgIGRhdGFQYWNrYWdlID0gY29udmVydFBhY2thZ2VGcm9tRGVzY3JpcHRvcihkZXNjcmlwdG9yLCB7XG4gICAgICBiYXNlcGF0aDogb3B0aW9ucz8uYmFzZXBhdGgsXG4gICAgfSkgYXMgdW5rbm93biBhcyBQYWNrYWdlXG4gIH1cblxuICByZXR1cm4geyAuLi5yZXBvcnQsIGRhdGFQYWNrYWdlIH1cbn1cbiJdfQ==
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,41 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { useRecording } from "vitest-polly";
3
+ import { loadDescriptor } from "../descriptor/index.js";
4
+ import { validatePackageMetadata } from "./validate.js";
5
+ useRecording();
6
+ describe("validatePackageMetadata", () => {
7
+ it("returns valid result for valid package", async () => {
8
+ const descriptor = {
9
+ name: "example-package",
10
+ resources: [
11
+ {
12
+ name: "resource-1",
13
+ path: "data.csv",
14
+ },
15
+ ],
16
+ };
17
+ const report = await validatePackageMetadata(descriptor);
18
+ expect(report.valid).toBe(true);
19
+ expect(report.errors).toEqual([]);
20
+ });
21
+ it("returns validation errors for invalid package", async () => {
22
+ const descriptor = {
23
+ name: 123, // Should be a string
24
+ resources: "not-an-array", // Should be an array
25
+ };
26
+ const report = await validatePackageMetadata(descriptor);
27
+ expect(report.valid).toBe(false);
28
+ expect(report.errors.length).toBeGreaterThan(0);
29
+ const error = report.errors[0];
30
+ expect(error).toBeDefined();
31
+ if (error) {
32
+ expect(error.pointer).toBe("/name");
33
+ }
34
+ });
35
+ it("should validate camtrap dp (#144)", async () => {
36
+ const descriptor = await loadDescriptor("https://raw.githubusercontent.com/tdwg/camtrap-dp/refs/tags/1.0.2/example/datapackage.json");
37
+ const report = await validatePackageMetadata(descriptor);
38
+ expect(report.valid).toBe(true);
39
+ });
40
+ });
41
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdGUuc3BlYy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3BhY2thZ2UvdmFsaWRhdGUuc3BlYy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxFQUFFLEVBQUUsTUFBTSxRQUFRLENBQUE7QUFDN0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGNBQWMsQ0FBQTtBQUMzQyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sd0JBQXdCLENBQUE7QUFDdkQsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sZUFBZSxDQUFBO0FBRXZELFlBQVksRUFBRSxDQUFBO0FBRWQsUUFBUSxDQUFDLHlCQUF5QixFQUFFLEdBQUcsRUFBRTtJQUN2QyxFQUFFLENBQUMsd0NBQXdDLEVBQUUsS0FBSyxJQUFJLEVBQUU7UUFDdEQsTUFBTSxVQUFVLEdBQUc7WUFDakIsSUFBSSxFQUFFLGlCQUFpQjtZQUN2QixTQUFTLEVBQUU7Z0JBQ1Q7b0JBQ0UsSUFBSSxFQUFFLFlBQVk7b0JBQ2xCLElBQUksRUFBRSxVQUFVO2lCQUNqQjthQUNGO1NBQ0YsQ0FBQTtRQUVELE1BQU0sTUFBTSxHQUFHLE1BQU0sdUJBQXVCLENBQUMsVUFBVSxDQUFDLENBQUE7UUFFeEQsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUE7UUFDL0IsTUFBTSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLENBQUE7SUFDbkMsQ0FBQyxDQUFDLENBQUE7SUFFRixFQUFFLENBQUMsK0NBQStDLEVBQUUsS0FBSyxJQUFJLEVBQUU7UUFDN0QsTUFBTSxVQUFVLEdBQUc7WUFDakIsSUFBSSxFQUFFLEdBQUcsRUFBRSxxQkFBcUI7WUFDaEMsU0FBUyxFQUFFLGNBQWMsRUFBRSxxQkFBcUI7U0FDakQsQ0FBQTtRQUVELE1BQU0sTUFBTSxHQUFHLE1BQU0sdUJBQXVCLENBQUMsVUFBVSxDQUFDLENBQUE7UUFFeEQsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUE7UUFDaEMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQyxDQUFBO1FBRS9DLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUE7UUFDOUIsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFBO1FBQzNCLElBQUksS0FBSyxFQUFFLENBQUM7WUFDVixNQUFNLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQTtRQUNyQyxDQUFDO0lBQ0gsQ0FBQyxDQUFDLENBQUE7SUFFRixFQUFFLENBQUMsbUNBQW1DLEVBQUUsS0FBSyxJQUFJLEVBQUU7UUFDakQsTUFBTSxVQUFVLEdBQUcsTUFBTSxjQUFjLENBQ3JDLDRGQUE0RixDQUM3RixDQUFBO1FBRUQsTUFBTSxNQUFNLEdBQUcsTUFBTSx1QkFBdUIsQ0FBQyxVQUFVLENBQUMsQ0FBQTtRQUN4RCxNQUFNLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQTtJQUNqQyxDQUFDLENBQUMsQ0FBQTtBQUNKLENBQUMsQ0FBQyxDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZGVzY3JpYmUsIGV4cGVjdCwgaXQgfSBmcm9tIFwidml0ZXN0XCJcbmltcG9ydCB7IHVzZVJlY29yZGluZyB9IGZyb20gXCJ2aXRlc3QtcG9sbHlcIlxuaW1wb3J0IHsgbG9hZERlc2NyaXB0b3IgfSBmcm9tIFwiLi4vZGVzY3JpcHRvci9pbmRleC50c1wiXG5pbXBvcnQgeyB2YWxpZGF0ZVBhY2thZ2VNZXRhZGF0YSB9IGZyb20gXCIuL3ZhbGlkYXRlLnRzXCJcblxudXNlUmVjb3JkaW5nKClcblxuZGVzY3JpYmUoXCJ2YWxpZGF0ZVBhY2thZ2VNZXRhZGF0YVwiLCAoKSA9PiB7XG4gIGl0KFwicmV0dXJucyB2YWxpZCByZXN1bHQgZm9yIHZhbGlkIHBhY2thZ2VcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGRlc2NyaXB0b3IgPSB7XG4gICAgICBuYW1lOiBcImV4YW1wbGUtcGFja2FnZVwiLFxuICAgICAgcmVzb3VyY2VzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBuYW1lOiBcInJlc291cmNlLTFcIixcbiAgICAgICAgICBwYXRoOiBcImRhdGEuY3N2XCIsXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH1cblxuICAgIGNvbnN0IHJlcG9ydCA9IGF3YWl0IHZhbGlkYXRlUGFja2FnZU1ldGFkYXRhKGRlc2NyaXB0b3IpXG5cbiAgICBleHBlY3QocmVwb3J0LnZhbGlkKS50b0JlKHRydWUpXG4gICAgZXhwZWN0KHJlcG9ydC5lcnJvcnMpLnRvRXF1YWwoW10pXG4gIH0pXG5cbiAgaXQoXCJyZXR1cm5zIHZhbGlkYXRpb24gZXJyb3JzIGZvciBpbnZhbGlkIHBhY2thZ2VcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGRlc2NyaXB0b3IgPSB7XG4gICAgICBuYW1lOiAxMjMsIC8vIFNob3VsZCBiZSBhIHN0cmluZ1xuICAgICAgcmVzb3VyY2VzOiBcIm5vdC1hbi1hcnJheVwiLCAvLyBTaG91bGQgYmUgYW4gYXJyYXlcbiAgICB9XG5cbiAgICBjb25zdCByZXBvcnQgPSBhd2FpdCB2YWxpZGF0ZVBhY2thZ2VNZXRhZGF0YShkZXNjcmlwdG9yKVxuXG4gICAgZXhwZWN0KHJlcG9ydC52YWxpZCkudG9CZShmYWxzZSlcbiAgICBleHBlY3QocmVwb3J0LmVycm9ycy5sZW5ndGgpLnRvQmVHcmVhdGVyVGhhbigwKVxuXG4gICAgY29uc3QgZXJyb3IgPSByZXBvcnQuZXJyb3JzWzBdXG4gICAgZXhwZWN0KGVycm9yKS50b0JlRGVmaW5lZCgpXG4gICAgaWYgKGVycm9yKSB7XG4gICAgICBleHBlY3QoZXJyb3IucG9pbnRlcikudG9CZShcIi9uYW1lXCIpXG4gICAgfVxuICB9KVxuXG4gIGl0KFwic2hvdWxkIHZhbGlkYXRlIGNhbXRyYXAgZHAgKCMxNDQpXCIsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBkZXNjcmlwdG9yID0gYXdhaXQgbG9hZERlc2NyaXB0b3IoXG4gICAgICBcImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS90ZHdnL2NhbXRyYXAtZHAvcmVmcy90YWdzLzEuMC4yL2V4YW1wbGUvZGF0YXBhY2thZ2UuanNvblwiLFxuICAgIClcblxuICAgIGNvbnN0IHJlcG9ydCA9IGF3YWl0IHZhbGlkYXRlUGFja2FnZU1ldGFkYXRhKGRlc2NyaXB0b3IpXG4gICAgZXhwZWN0KHJlcG9ydC52YWxpZCkudG9CZSh0cnVlKVxuICB9KVxufSlcbiJdfQ==
@@ -0,0 +1,2 @@
1
+ export declare function resolveBasepath(path: string): Promise<string>;
2
+ export declare function getBasepath(path: string): string;
@@ -0,0 +1,25 @@
1
+ import { node } from "../platform/index.js";
2
+ import { isRemotePath } from "./path.js";
3
+ export async function resolveBasepath(path) {
4
+ const isRemote = isRemotePath(path);
5
+ // Resolves redirects
6
+ if (isRemote) {
7
+ const url = new URL(path);
8
+ const response = await fetch(url.toString(), { method: "HEAD" });
9
+ path = response.url;
10
+ }
11
+ return getBasepath(path);
12
+ }
13
+ export function getBasepath(path) {
14
+ const isRemote = isRemotePath(path);
15
+ if (isRemote) {
16
+ const normalizedPath = new URL(path).toString();
17
+ return normalizedPath.split("/").slice(0, -1).join("/");
18
+ }
19
+ if (!node) {
20
+ throw new Error("File system is not supported in this environment");
21
+ }
22
+ const resolvedPath = node.path.resolve(path);
23
+ return node.path.relative(process.cwd(), node.path.parse(resolvedPath).dir);
24
+ }
25
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZXBhdGguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9wYXRoL2Jhc2VwYXRoLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQTtBQUMzQyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBRXhDLE1BQU0sQ0FBQyxLQUFLLFVBQVUsZUFBZSxDQUFDLElBQVk7SUFDaEQsTUFBTSxRQUFRLEdBQUcsWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFBO0lBRW5DLHFCQUFxQjtJQUNyQixJQUFJLFFBQVEsRUFBRSxDQUFDO1FBQ2IsTUFBTSxHQUFHLEdBQUcsSUFBSSxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUE7UUFDekIsTUFBTSxRQUFRLEdBQUcsTUFBTSxLQUFLLENBQUMsR0FBRyxDQUFDLFFBQVEsRUFBRSxFQUFFLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUE7UUFDaEUsSUFBSSxHQUFHLFFBQVEsQ0FBQyxHQUFHLENBQUE7SUFDckIsQ0FBQztJQUVELE9BQU8sV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFBO0FBQzFCLENBQUM7QUFFRCxNQUFNLFVBQVUsV0FBVyxDQUFDLElBQVk7SUFDdEMsTUFBTSxRQUFRLEdBQUcsWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFBO0lBRW5DLElBQUksUUFBUSxFQUFFLENBQUM7UUFDYixNQUFNLGNBQWMsR0FBRyxJQUFJLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQTtRQUMvQyxPQUFPLGNBQWMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQTtJQUN6RCxDQUFDO0lBRUQsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ1YsTUFBTSxJQUFJLEtBQUssQ0FBQyxrREFBa0QsQ0FBQyxDQUFBO0lBQ3JFLENBQUM7SUFFRCxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQTtJQUM1QyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQTtBQUM3RSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgbm9kZSB9IGZyb20gXCIuLi9wbGF0Zm9ybS9pbmRleC50c1wiXG5pbXBvcnQgeyBpc1JlbW90ZVBhdGggfSBmcm9tIFwiLi9wYXRoLnRzXCJcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlc29sdmVCYXNlcGF0aChwYXRoOiBzdHJpbmcpIHtcbiAgY29uc3QgaXNSZW1vdGUgPSBpc1JlbW90ZVBhdGgocGF0aClcblxuICAvLyBSZXNvbHZlcyByZWRpcmVjdHNcbiAgaWYgKGlzUmVtb3RlKSB7XG4gICAgY29uc3QgdXJsID0gbmV3IFVSTChwYXRoKVxuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2godXJsLnRvU3RyaW5nKCksIHsgbWV0aG9kOiBcIkhFQURcIiB9KVxuICAgIHBhdGggPSByZXNwb25zZS51cmxcbiAgfVxuXG4gIHJldHVybiBnZXRCYXNlcGF0aChwYXRoKVxufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0QmFzZXBhdGgocGF0aDogc3RyaW5nKSB7XG4gIGNvbnN0IGlzUmVtb3RlID0gaXNSZW1vdGVQYXRoKHBhdGgpXG5cbiAgaWYgKGlzUmVtb3RlKSB7XG4gICAgY29uc3Qgbm9ybWFsaXplZFBhdGggPSBuZXcgVVJMKHBhdGgpLnRvU3RyaW5nKClcbiAgICByZXR1cm4gbm9ybWFsaXplZFBhdGguc3BsaXQoXCIvXCIpLnNsaWNlKDAsIC0xKS5qb2luKFwiL1wiKVxuICB9XG5cbiAgaWYgKCFub2RlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFwiRmlsZSBzeXN0ZW0gaXMgbm90IHN1cHBvcnRlZCBpbiB0aGlzIGVudmlyb25tZW50XCIpXG4gIH1cblxuICBjb25zdCByZXNvbHZlZFBhdGggPSBub2RlLnBhdGgucmVzb2x2ZShwYXRoKVxuICByZXR1cm4gbm9kZS5wYXRoLnJlbGF0aXZlKHByb2Nlc3MuY3dkKCksIG5vZGUucGF0aC5wYXJzZShyZXNvbHZlZFBhdGgpLmRpcilcbn1cbiJdfQ==
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,55 @@
1
+ import { join } from "node:path";
2
+ import { describe, expect, it } from "vitest";
3
+ import { getBasepath } from "./basepath.js";
4
+ describe("getBasepath", () => {
5
+ it.each([
6
+ {
7
+ description: "http URL with file",
8
+ path: "http://example.com/path/to/file.txt",
9
+ basepath: "http://example.com/path/to",
10
+ },
11
+ {
12
+ description: "https URL with file",
13
+ path: "https://example.com/path/to/file.txt",
14
+ basepath: "https://example.com/path/to",
15
+ },
16
+ {
17
+ description: "URL with query parameters",
18
+ path: "https://example.com/path/to/file.txt?query=param",
19
+ basepath: "https://example.com/path/to",
20
+ },
21
+ {
22
+ description: "URL with hash",
23
+ path: "https://example.com/path/to/file.txt#section",
24
+ basepath: "https://example.com/path/to",
25
+ },
26
+ {
27
+ description: "URL with no file",
28
+ path: "https://example.com/path/to/",
29
+ basepath: "https://example.com/path/to",
30
+ },
31
+ {
32
+ description: "URL with only domain",
33
+ path: "https://example.com",
34
+ basepath: "https://example.com",
35
+ },
36
+ {
37
+ description: "local file path",
38
+ path: "some/path/to/file.txt",
39
+ basepath: join("some", "path", "to"),
40
+ },
41
+ {
42
+ description: "local path with no file",
43
+ path: "some/path/to/",
44
+ basepath: join("some", "path"),
45
+ },
46
+ {
47
+ description: "root level file",
48
+ path: "file.txt",
49
+ basepath: "",
50
+ },
51
+ ])("$description", ({ path, basepath }) => {
52
+ expect(getBasepath(path)).toEqual(basepath);
53
+ });
54
+ });
55
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZXBhdGguc3BlYy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3BhdGgvYmFzZXBhdGguc3BlYy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBQ2hDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLEVBQUUsRUFBRSxNQUFNLFFBQVEsQ0FBQTtBQUM3QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZUFBZSxDQUFBO0FBRTNDLFFBQVEsQ0FBQyxhQUFhLEVBQUUsR0FBRyxFQUFFO0lBQzNCLEVBQUUsQ0FBQyxJQUFJLENBQUM7UUFDTjtZQUNFLFdBQVcsRUFBRSxvQkFBb0I7WUFDakMsSUFBSSxFQUFFLHFDQUFxQztZQUMzQyxRQUFRLEVBQUUsNEJBQTRCO1NBQ3ZDO1FBQ0Q7WUFDRSxXQUFXLEVBQUUscUJBQXFCO1lBQ2xDLElBQUksRUFBRSxzQ0FBc0M7WUFDNUMsUUFBUSxFQUFFLDZCQUE2QjtTQUN4QztRQUNEO1lBQ0UsV0FBVyxFQUFFLDJCQUEyQjtZQUN4QyxJQUFJLEVBQUUsa0RBQWtEO1lBQ3hELFFBQVEsRUFBRSw2QkFBNkI7U0FDeEM7UUFDRDtZQUNFLFdBQVcsRUFBRSxlQUFlO1lBQzVCLElBQUksRUFBRSw4Q0FBOEM7WUFDcEQsUUFBUSxFQUFFLDZCQUE2QjtTQUN4QztRQUNEO1lBQ0UsV0FBVyxFQUFFLGtCQUFrQjtZQUMvQixJQUFJLEVBQUUsOEJBQThCO1lBQ3BDLFFBQVEsRUFBRSw2QkFBNkI7U0FDeEM7UUFDRDtZQUNFLFdBQVcsRUFBRSxzQkFBc0I7WUFDbkMsSUFBSSxFQUFFLHFCQUFxQjtZQUMzQixRQUFRLEVBQUUscUJBQXFCO1NBQ2hDO1FBQ0Q7WUFDRSxXQUFXLEVBQUUsaUJBQWlCO1lBQzlCLElBQUksRUFBRSx1QkFBdUI7WUFDN0IsUUFBUSxFQUFFLElBQUksQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLElBQUksQ0FBQztTQUNyQztRQUNEO1lBQ0UsV0FBVyxFQUFFLHlCQUF5QjtZQUN0QyxJQUFJLEVBQUUsZUFBZTtZQUNyQixRQUFRLEVBQUUsSUFBSSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUM7U0FDL0I7UUFDRDtZQUNFLFdBQVcsRUFBRSxpQkFBaUI7WUFDOUIsSUFBSSxFQUFFLFVBQVU7WUFDaEIsUUFBUSxFQUFFLEVBQUU7U0FDYjtLQUNGLENBQUMsQ0FBQyxjQUFjLEVBQUUsQ0FBQyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsRUFBRSxFQUFFO1FBQ3hDLE1BQU0sQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUE7SUFDN0MsQ0FBQyxDQUFDLENBQUE7QUFDSixDQUFDLENBQUMsQ0FBQSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGpvaW4gfSBmcm9tIFwibm9kZTpwYXRoXCJcbmltcG9ydCB7IGRlc2NyaWJlLCBleHBlY3QsIGl0IH0gZnJvbSBcInZpdGVzdFwiXG5pbXBvcnQgeyBnZXRCYXNlcGF0aCB9IGZyb20gXCIuL2Jhc2VwYXRoLnRzXCJcblxuZGVzY3JpYmUoXCJnZXRCYXNlcGF0aFwiLCAoKSA9PiB7XG4gIGl0LmVhY2goW1xuICAgIHtcbiAgICAgIGRlc2NyaXB0aW9uOiBcImh0dHAgVVJMIHdpdGggZmlsZVwiLFxuICAgICAgcGF0aDogXCJodHRwOi8vZXhhbXBsZS5jb20vcGF0aC90by9maWxlLnR4dFwiLFxuICAgICAgYmFzZXBhdGg6IFwiaHR0cDovL2V4YW1wbGUuY29tL3BhdGgvdG9cIixcbiAgICB9LFxuICAgIHtcbiAgICAgIGRlc2NyaXB0aW9uOiBcImh0dHBzIFVSTCB3aXRoIGZpbGVcIixcbiAgICAgIHBhdGg6IFwiaHR0cHM6Ly9leGFtcGxlLmNvbS9wYXRoL3RvL2ZpbGUudHh0XCIsXG4gICAgICBiYXNlcGF0aDogXCJodHRwczovL2V4YW1wbGUuY29tL3BhdGgvdG9cIixcbiAgICB9LFxuICAgIHtcbiAgICAgIGRlc2NyaXB0aW9uOiBcIlVSTCB3aXRoIHF1ZXJ5IHBhcmFtZXRlcnNcIixcbiAgICAgIHBhdGg6IFwiaHR0cHM6Ly9leGFtcGxlLmNvbS9wYXRoL3RvL2ZpbGUudHh0P3F1ZXJ5PXBhcmFtXCIsXG4gICAgICBiYXNlcGF0aDogXCJodHRwczovL2V4YW1wbGUuY29tL3BhdGgvdG9cIixcbiAgICB9LFxuICAgIHtcbiAgICAgIGRlc2NyaXB0aW9uOiBcIlVSTCB3aXRoIGhhc2hcIixcbiAgICAgIHBhdGg6IFwiaHR0cHM6Ly9leGFtcGxlLmNvbS9wYXRoL3RvL2ZpbGUudHh0I3NlY3Rpb25cIixcbiAgICAgIGJhc2VwYXRoOiBcImh0dHBzOi8vZXhhbXBsZS5jb20vcGF0aC90b1wiLFxuICAgIH0sXG4gICAge1xuICAgICAgZGVzY3JpcHRpb246IFwiVVJMIHdpdGggbm8gZmlsZVwiLFxuICAgICAgcGF0aDogXCJodHRwczovL2V4YW1wbGUuY29tL3BhdGgvdG8vXCIsXG4gICAgICBiYXNlcGF0aDogXCJodHRwczovL2V4YW1wbGUuY29tL3BhdGgvdG9cIixcbiAgICB9LFxuICAgIHtcbiAgICAgIGRlc2NyaXB0aW9uOiBcIlVSTCB3aXRoIG9ubHkgZG9tYWluXCIsXG4gICAgICBwYXRoOiBcImh0dHBzOi8vZXhhbXBsZS5jb21cIixcbiAgICAgIGJhc2VwYXRoOiBcImh0dHBzOi8vZXhhbXBsZS5jb21cIixcbiAgICB9LFxuICAgIHtcbiAgICAgIGRlc2NyaXB0aW9uOiBcImxvY2FsIGZpbGUgcGF0aFwiLFxuICAgICAgcGF0aDogXCJzb21lL3BhdGgvdG8vZmlsZS50eHRcIixcbiAgICAgIGJhc2VwYXRoOiBqb2luKFwic29tZVwiLCBcInBhdGhcIiwgXCJ0b1wiKSxcbiAgICB9LFxuICAgIHtcbiAgICAgIGRlc2NyaXB0aW9uOiBcImxvY2FsIHBhdGggd2l0aCBubyBmaWxlXCIsXG4gICAgICBwYXRoOiBcInNvbWUvcGF0aC90by9cIixcbiAgICAgIGJhc2VwYXRoOiBqb2luKFwic29tZVwiLCBcInBhdGhcIiksXG4gICAgfSxcbiAgICB7XG4gICAgICBkZXNjcmlwdGlvbjogXCJyb290IGxldmVsIGZpbGVcIixcbiAgICAgIHBhdGg6IFwiZmlsZS50eHRcIixcbiAgICAgIGJhc2VwYXRoOiBcIlwiLFxuICAgIH0sXG4gIF0pKFwiJGRlc2NyaXB0aW9uXCIsICh7IHBhdGgsIGJhc2VwYXRoIH0pID0+IHtcbiAgICBleHBlY3QoZ2V0QmFzZXBhdGgocGF0aCkpLnRvRXF1YWwoYmFzZXBhdGgpXG4gIH0pXG59KVxuIl19
@@ -0,0 +1,3 @@
1
+ export declare function denormalizePath(path: string, options: {
2
+ basepath?: string;
3
+ }): string;
@@ -0,0 +1,29 @@
1
+ import { node } from "../platform/index.js";
2
+ import { isRemotePath } from "./path.js";
3
+ export function denormalizePath(path, options) {
4
+ const isPathRemote = isRemotePath(path);
5
+ const isBasepathRemote = isRemotePath(options.basepath ?? "");
6
+ if (isPathRemote) {
7
+ return new URL(path).toString();
8
+ }
9
+ if (isBasepathRemote) {
10
+ const basepath = new URL(options.basepath ?? "").toString();
11
+ if (!path.startsWith(basepath)) {
12
+ throw new Error(`Path ${path} is not a subpath of ${options.basepath}`);
13
+ }
14
+ const relative = path.replace(`${basepath}/`, "");
15
+ return relative;
16
+ }
17
+ if (!node) {
18
+ throw new Error("File system is not supported in this environment");
19
+ }
20
+ const normalizedPath = node.path.resolve(path);
21
+ const normalizedBasepath = node.path.resolve(options.basepath ?? "");
22
+ if (!normalizedPath.startsWith(normalizedBasepath)) {
23
+ throw new Error(`Path ${path} is not a subpath of ${options.basepath}`);
24
+ }
25
+ // The Data Package standard requires "/" as the path separator
26
+ const relative = node.path.relative(normalizedBasepath, normalizedPath);
27
+ return relative.split(node.path.sep).join("/");
28
+ }
29
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVub3JtYWxpemUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9wYXRoL2Rlbm9ybWFsaXplLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQTtBQUMzQyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBRXhDLE1BQU0sVUFBVSxlQUFlLENBQUMsSUFBWSxFQUFFLE9BQThCO0lBQzFFLE1BQU0sWUFBWSxHQUFHLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQTtJQUN2QyxNQUFNLGdCQUFnQixHQUFHLFlBQVksQ0FBQyxPQUFPLENBQUMsUUFBUSxJQUFJLEVBQUUsQ0FBQyxDQUFBO0lBRTdELElBQUksWUFBWSxFQUFFLENBQUM7UUFDakIsT0FBTyxJQUFJLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQTtJQUNqQyxDQUFDO0lBRUQsSUFBSSxnQkFBZ0IsRUFBRSxDQUFDO1FBQ3JCLE1BQU0sUUFBUSxHQUFHLElBQUksR0FBRyxDQUFDLE9BQU8sQ0FBQyxRQUFRLElBQUksRUFBRSxDQUFDLENBQUMsUUFBUSxFQUFFLENBQUE7UUFFM0QsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztZQUMvQixNQUFNLElBQUksS0FBSyxDQUFDLFFBQVEsSUFBSSx3QkFBd0IsT0FBTyxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUE7UUFDekUsQ0FBQztRQUVELE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxRQUFRLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQTtRQUNqRCxPQUFPLFFBQVEsQ0FBQTtJQUNqQixDQUFDO0lBRUQsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ1YsTUFBTSxJQUFJLEtBQUssQ0FBQyxrREFBa0QsQ0FBQyxDQUFBO0lBQ3JFLENBQUM7SUFFRCxNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQTtJQUM5QyxNQUFNLGtCQUFrQixHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxRQUFRLElBQUksRUFBRSxDQUFDLENBQUE7SUFFcEUsSUFBSSxDQUFDLGNBQWMsQ0FBQyxVQUFVLENBQUMsa0JBQWtCLENBQUMsRUFBRSxDQUFDO1FBQ25ELE1BQU0sSUFBSSxLQUFLLENBQUMsUUFBUSxJQUFJLHdCQUF3QixPQUFPLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQTtJQUN6RSxDQUFDO0lBRUQsK0RBQStEO0lBQy9ELE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLGtCQUFrQixFQUFFLGNBQWMsQ0FBQyxDQUFBO0lBQ3ZFLE9BQU8sUUFBUSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQTtBQUNoRCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgbm9kZSB9IGZyb20gXCIuLi9wbGF0Zm9ybS9pbmRleC50c1wiXG5pbXBvcnQgeyBpc1JlbW90ZVBhdGggfSBmcm9tIFwiLi9wYXRoLnRzXCJcblxuZXhwb3J0IGZ1bmN0aW9uIGRlbm9ybWFsaXplUGF0aChwYXRoOiBzdHJpbmcsIG9wdGlvbnM6IHsgYmFzZXBhdGg/OiBzdHJpbmcgfSkge1xuICBjb25zdCBpc1BhdGhSZW1vdGUgPSBpc1JlbW90ZVBhdGgocGF0aClcbiAgY29uc3QgaXNCYXNlcGF0aFJlbW90ZSA9IGlzUmVtb3RlUGF0aChvcHRpb25zLmJhc2VwYXRoID8/IFwiXCIpXG5cbiAgaWYgKGlzUGF0aFJlbW90ZSkge1xuICAgIHJldHVybiBuZXcgVVJMKHBhdGgpLnRvU3RyaW5nKClcbiAgfVxuXG4gIGlmIChpc0Jhc2VwYXRoUmVtb3RlKSB7XG4gICAgY29uc3QgYmFzZXBhdGggPSBuZXcgVVJMKG9wdGlvbnMuYmFzZXBhdGggPz8gXCJcIikudG9TdHJpbmcoKVxuXG4gICAgaWYgKCFwYXRoLnN0YXJ0c1dpdGgoYmFzZXBhdGgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFBhdGggJHtwYXRofSBpcyBub3QgYSBzdWJwYXRoIG9mICR7b3B0aW9ucy5iYXNlcGF0aH1gKVxuICAgIH1cblxuICAgIGNvbnN0IHJlbGF0aXZlID0gcGF0aC5yZXBsYWNlKGAke2Jhc2VwYXRofS9gLCBcIlwiKVxuICAgIHJldHVybiByZWxhdGl2ZVxuICB9XG5cbiAgaWYgKCFub2RlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFwiRmlsZSBzeXN0ZW0gaXMgbm90IHN1cHBvcnRlZCBpbiB0aGlzIGVudmlyb25tZW50XCIpXG4gIH1cblxuICBjb25zdCBub3JtYWxpemVkUGF0aCA9IG5vZGUucGF0aC5yZXNvbHZlKHBhdGgpXG4gIGNvbnN0IG5vcm1hbGl6ZWRCYXNlcGF0aCA9IG5vZGUucGF0aC5yZXNvbHZlKG9wdGlvbnMuYmFzZXBhdGggPz8gXCJcIilcblxuICBpZiAoIW5vcm1hbGl6ZWRQYXRoLnN0YXJ0c1dpdGgobm9ybWFsaXplZEJhc2VwYXRoKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgUGF0aCAke3BhdGh9IGlzIG5vdCBhIHN1YnBhdGggb2YgJHtvcHRpb25zLmJhc2VwYXRofWApXG4gIH1cblxuICAvLyBUaGUgRGF0YSBQYWNrYWdlIHN0YW5kYXJkIHJlcXVpcmVzIFwiL1wiIGFzIHRoZSBwYXRoIHNlcGFyYXRvclxuICBjb25zdCByZWxhdGl2ZSA9IG5vZGUucGF0aC5yZWxhdGl2ZShub3JtYWxpemVkQmFzZXBhdGgsIG5vcm1hbGl6ZWRQYXRoKVxuICByZXR1cm4gcmVsYXRpdmUuc3BsaXQobm9kZS5wYXRoLnNlcCkuam9pbihcIi9cIilcbn1cbiJdfQ==
@@ -0,0 +1 @@
1
+ export {};