@arcgis/core-adapter 4.32.0-next.8 → 4.32.0-next.81

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcgis/core-adapter",
3
- "version": "4.32.0-next.8",
3
+ "version": "4.32.0-next.81",
4
4
  "description": "ArcGIS Core Adapter",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -13,6 +13,9 @@
13
13
  "require": "./dist/index.cjs"
14
14
  }
15
15
  },
16
+ "files": [
17
+ "dist/"
18
+ ],
16
19
  "license": "SEE LICENSE IN LICENSE.md",
17
20
  "dependencies": {
18
21
  "tslib": "^2.7.0"
@@ -1,3 +0,0 @@
1
- Reading typings file...
2
- Modules converted to core-adapter: 946
3
- Adapter file generated.
@@ -1,419 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import ts from "typescript";
4
- import resolvePkg from "resolve-pkg";
5
- import type { SourceFile } from "ts-morph";
6
- import { Project } from "ts-morph";
7
- import { fileURLToPath } from "url";
8
-
9
- const dirname = path.dirname(fileURLToPath(import.meta.url));
10
-
11
- /**
12
- * Collect the details of a type we are interested in
13
- */
14
- interface TypeInfo {
15
- // The path of the module that contains the type. For example: `esri/identity/IdentityManager`
16
- amdModulePath: string;
17
- // The path of the module that contains the type. For example: `@arcgis/core/identity/IdentityManager`
18
- esmModulePath?: string;
19
- // The name of the type. For example: `__esri.Credential`
20
- typeName: string;
21
- // If the type is a class and has at least one constructor, we collect the parameters of the constructor
22
- constructorParameters?: ParameterInfo[];
23
- // If the type is a singleton then instanceType will be true
24
- instanceType?: boolean;
25
- }
26
-
27
- /**
28
- * Describe a parameter of a constructor
29
- */
30
- interface ParameterInfo {
31
- // The name of the parameter
32
- name: string;
33
- // The type of the parameter
34
- type: string;
35
- }
36
-
37
- const nativeTypes: string[] = [
38
- "number",
39
- "string",
40
- "boolean",
41
- "null",
42
- "undefined",
43
- "object",
44
- "symbol",
45
- "any",
46
- "void",
47
- "never",
48
- "array",
49
- ];
50
-
51
- const nativeArrayTypes = nativeTypes.map((x) => `${x}[]`);
52
- const nativeGenericTypes = nativeTypes.map((x) => `<${x}>`);
53
-
54
- // Modules to ignore
55
- const ignoreExports: string[] = [
56
- // declared as a namespace
57
- "esri/core/units",
58
- ];
59
-
60
- // Module that returns an instance of a class
61
- const singletons = new Map<string, string>([["esri/identity/IdentityManager", "__esri.IdentityManager"]]);
62
-
63
- // The header of the index file
64
- // We want to detect if the environment is AMD
65
- // Define the AMD import module global
66
- const indexHeader = `
67
- const isAMD = typeof window !== "undefined" && "$arcgis" in window && typeof window.$arcgis === "object" && "import" in window.$arcgis && !("forceESM" in window.$arcgis);
68
-
69
- declare global {
70
- interface Window {
71
- $arcgis: { import: <T>(modules: string | string[], forceESM?: boolean) => Promise<T> };
72
- }
73
- }
74
-
75
- interface DefaultModule<T> {
76
- default: T;
77
- }
78
-
79
-
80
- function isDefaultModule<T>(module: DefaultModule<T> | T): module is DefaultModule<T> {
81
- return (module as DefaultModule<T>).default !== undefined;
82
- }
83
-
84
- /**
85
- * Load an undocumented module respecting the current environment (AMD or ESM).
86
- * The module type will certainly be \`any\` as it is not documented.
87
- * For ESM, if the module exports a default, it will be returned, otherwise the module itself will be returned.
88
- * @param modulePath - The path to the module to load, example: "@arcgis/core/Map"
89
- * @param deferredImport - A function that should call import() and return the module, example: () => import("@arcgis/core/Map")
90
- * @returns - Promise that resolves to the module
91
- */
92
- export async function loadUndocumentedModule<T>(modulePath: string, deferredImport: () => Promise<T>): Promise<T> {
93
- if (isAMD) {
94
- return await window.$arcgis.import(modulePath);
95
- }
96
- const module = deferredImport();
97
- return isDefaultModule(module) ? module.default : module;
98
- }
99
- `;
100
-
101
- class PublicTypeValidator {
102
- project: Project;
103
- source: SourceFile | undefined;
104
-
105
- constructor() {
106
- this.project = new Project();
107
- const coreInterfacesPath = resolvePkg("@arcgis/core/interfaces.d.ts");
108
- if (!coreInterfacesPath) {
109
- console.error("Could not find @arcgis/core/interfaces.d.ts. Make sure you have installed @arcgis/core.");
110
- return;
111
- }
112
-
113
- this.source = this.project.addSourceFileAtPath(coreInterfacesPath);
114
- }
115
-
116
- validateType(typeName: string): boolean {
117
- if (!this.source) {
118
- return false;
119
- }
120
-
121
- const [namespaceName, name] = typeName.split(".");
122
- const namespace = this.source.getModule(namespaceName);
123
- if (!namespace) {
124
- return false;
125
- }
126
-
127
- // Under the namespace `__esri`, we can find type as class, interface or namespace
128
- // ```
129
- // declare namespace __esri {
130
- // export interface Credential { ... }
131
- // export class Credential { ... }
132
- // namespace geometry { ... }
133
- // }
134
- // ```
135
- return !!namespace.getClass(name) || !!namespace.getInterface(name) || !!namespace.getModule(name);
136
- }
137
- }
138
-
139
- function generate(): void {
140
- console.log("Reading typings file...");
141
-
142
- // Load our esm import references
143
- const esmImportReferencesContent: string = fs.readFileSync(
144
- path.join(dirname, "../support/api-reference-esm-imports.json"),
145
- "utf8",
146
- );
147
- const amdImportReferences = JSON.parse(esmImportReferencesContent) as Record<string, string>;
148
- const amdImportReferencesKeys = Object.keys(amdImportReferences);
149
-
150
- // Start building the index file
151
- // At the top we add the amd logic
152
- const indexFileStatements: string[] = [];
153
- indexFileStatements.push(indexHeader);
154
-
155
- // Create a ts program with the typings file
156
- // Also create a type checker
157
- const typingsFilepath = path.resolve(dirname, "../support/arcgis.d.ts");
158
- const program = ts.createProgram([typingsFilepath], {});
159
- const checker = program.getTypeChecker();
160
- const typingsProgram = program.getSourceFile(typingsFilepath);
161
- if (!typingsProgram) {
162
- console.error(`Could not find source file: ${typingsFilepath}`);
163
- return;
164
- }
165
-
166
- const publicTypeValidator = new PublicTypeValidator();
167
-
168
- // We will visit the typings and extract the symbols we need
169
- // Add the singletons to the typeInfos array
170
- const typeInfos: TypeInfo[] = [...singletons.entries()].map(([amdModulePath, typeName]) => ({
171
- amdModulePath,
172
- esmModulePath: convertAmdToEsmPath(amdModulePath),
173
- typeName,
174
- instanceType: true,
175
- }));
176
-
177
- /** Create a visitor function for the context */
178
- function createVisitor(context: ts.TransformationContext): ts.Visitor<ts.Node, ts.Node> {
179
- return function visit(node: ts.Node): ts.Node {
180
- // Visit each child node
181
- node = ts.visitEachChild(node, visit, context);
182
-
183
- // We are only interested in module declarations
184
- // Example: `declare module "esri/identity/IdentityManager" {`
185
- if (!ts.isModuleDeclaration(node)) {
186
- return node;
187
- }
188
-
189
- // Only include imports that are in the import dictionary
190
- // or are part of "esri/applications" modules
191
- const amdModulePath = node.name.text;
192
- if (!amdImportReferencesKeys.includes(amdModulePath) && !amdModulePath.includes("esri/applications")) {
193
- return node;
194
- }
195
-
196
- // Ignore modules that are in the ignore list and the singletons that are already in the typeInfos array
197
- if (ignoreModule(amdModulePath) || singletons.has(amdModulePath)) {
198
- return node;
199
- }
200
-
201
- // Loop thru the module body
202
- node.body?.forEachChild((statement) => {
203
- // We are only interested in import equals declarations inside ModuleDeclarations
204
- // For example:
205
- // declare module "esri/identity/Credential" {
206
- // import Credential = __esri.Credential; << This is what we are interested in
207
- // export = Credential;
208
- // }
209
- if (!ts.isImportEqualsDeclaration(statement)) {
210
- return;
211
- }
212
-
213
- // Get the type name, i.g. `__esri.Credential` and validate that it is a class or interface
214
- // in the public interfaces.
215
- const typeName = statement.moduleReference.getText(typingsProgram);
216
- if (!publicTypeValidator.validateType(typeName)) {
217
- return;
218
- }
219
-
220
- // Validate that we can find the esm module file
221
- const esmModulePath = convertAmdToEsmPath(amdModulePath);
222
- const resolvedEsmModulePath = resolvePkg(esmModulePath);
223
- if (!resolvedEsmModulePath || !fs.existsSync(resolvedEsmModulePath)) {
224
- console.error(`Could not find esm module for: ${esmModulePath}`);
225
- return;
226
- }
227
-
228
- // If the type has a constructor, we want to extract the parameters
229
- // to inject the new function
230
- const constructorParameters = extractConstructorParameters(statement);
231
-
232
- // Get the symbol and extract details
233
- typeInfos.push({ amdModulePath, esmModulePath, typeName, constructorParameters });
234
- });
235
-
236
- return node;
237
- };
238
- }
239
-
240
- /** This is our entry point for the transformer */
241
- function extractTypeInfos(context: ts.TransformationContext): ts.Transformer<ts.Node> {
242
- const visit = createVisitor(context);
243
- return (node: ts.Node) => ts.visitNode(node, visit);
244
- }
245
-
246
- /** Serialize a class symbol information */
247
- function extractConstructorParameters(statement: ts.ImportEqualsDeclaration): ParameterInfo[] | undefined {
248
- // Get the symbol of the module reference
249
- // Example: `import Credential = __esri.Credential;`
250
- // In this example, `__esri.Credential` is the module reference
251
- // We want to get the type of `__esri.Credential`
252
- const symbol = checker.getSymbolAtLocation(statement.moduleReference);
253
- if (!symbol) {
254
- throw new Error("Symbol not found");
255
- }
256
-
257
- // The constructor parameters are only relevant if the type has a constructor signature.
258
- // We want to extract the constructor parameters for the first constructor signature.
259
- // Example: `declare class Credential { constructor(properties: CredentialProperties); }`
260
- // constructorParameters will be an array with one item: `{ name: "properties", type: "CredentialProperties" }` or undefined.
261
- return checker
262
- .getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration!)
263
- .getConstructSignatures()
264
- .at(0)
265
- ?.getParameters()
266
- .map<ParameterInfo>((parameterSymbol: ts.Symbol) => ({
267
- name: parameterSymbol.getName(),
268
- type: checker.typeToString(
269
- checker.getTypeOfSymbolAtLocation(parameterSymbol, parameterSymbol.valueDeclaration!),
270
- ),
271
- }));
272
- }
273
-
274
- // Use the transformer to visit the typings file
275
- ts.transform(typingsProgram, [extractTypeInfos]);
276
-
277
- // At this point the typeInfos array contains all the symbols we are interested in
278
- for (const typeInfo of typeInfos) {
279
- // Generate the import function
280
- indexFileStatements.push(generateImportFunction(typeInfo));
281
-
282
- // If we have constructor parameters, generate the new function
283
- if (typeInfo.constructorParameters) {
284
- indexFileStatements.push(generateNewFunction(typeInfo));
285
- }
286
- }
287
-
288
- console.log("Modules converted to core-adapter: ", typeInfos.length);
289
-
290
- const indexContent = indexFileStatements.join("\n");
291
- fs.writeFile("src/index.ts", indexContent, (err) => {
292
- if (err) {
293
- console.error("Error generating adapter file:", err);
294
- } else {
295
- console.log("Adapter file generated.");
296
- }
297
- });
298
- }
299
-
300
- function generateNewFunction(entry: TypeInfo): string {
301
- const { amdModulePath, typeName, constructorParameters } = entry;
302
- if (!constructorParameters) {
303
- throw new Error("Constructor parameters are required");
304
- }
305
-
306
- const functionNameSuffix = convertToPascalCase(amdModulePath);
307
-
308
- // Generate the parameters declarations and the call arguments
309
- const parameterDeclarations: string[] = [];
310
- const callArgumentsParts: string[] = [];
311
- for (const parameterInfo of constructorParameters) {
312
- callArgumentsParts.push(parameterInfo.name);
313
-
314
- // Do we have a union type?
315
- if (parameterInfo.type.includes("|")) {
316
- parameterDeclarations.push(processUnionType(parameterInfo));
317
- continue;
318
- }
319
-
320
- // Do we have a native type?
321
- if (nativeTypes.some((x) => x.includes(parameterInfo.type || ""))) {
322
- parameterDeclarations.push(`${parameterInfo.name}: ${parameterInfo.type}`);
323
- continue;
324
- }
325
-
326
- // Must be an esri type
327
- parameterDeclarations.push(`${parameterInfo.name}: __esri.${parameterInfo.type}`);
328
- }
329
-
330
- const parametersDeclaration = parameterDeclarations.join(", ");
331
- const callArguments = callArgumentsParts.join(", ");
332
-
333
- return `
334
- export async function new${functionNameSuffix}(${parametersDeclaration}): Promise<${typeName}> {
335
- const ModConstructor = await import${functionNameSuffix}();
336
- return new ModConstructor(${callArguments});
337
- }`;
338
- }
339
-
340
- /**
341
- * Process a parameter defined as a union type
342
- */
343
- function processUnionType(parameterInfo: ParameterInfo): string {
344
- // Split the union type into parts and process each part
345
- const unionedTypesParts = parameterInfo.type.split("|");
346
- const correctedUnionedTypes: string[] = [];
347
- for (const unionTypesPart of unionedTypesParts) {
348
- // Is the part a native type?
349
- if (nativeArrayTypes.some((x) => unionTypesPart.includes(x))) {
350
- correctedUnionedTypes.push(unionTypesPart);
351
- continue;
352
- }
353
-
354
- // Is the part a Collection type?
355
- if (unionTypesPart.includes("Collection<")) {
356
- // Handle Collection types
357
- if (nativeGenericTypes.some((x) => unionTypesPart.includes(x))) {
358
- correctedUnionedTypes.push(`__esri.${unionTypesPart.trim()}`);
359
- } else {
360
- const v = unionTypesPart.replace(/<(?<esriTypeName>[^>]+)>/gu, "<__esri.$1>");
361
- correctedUnionedTypes.push(`__esri.${v.trim()}`);
362
- }
363
- continue;
364
- }
365
-
366
- // Must be an esri type
367
- correctedUnionedTypes.push(`__esri.${unionTypesPart.trim()}`);
368
- }
369
-
370
- // Re-assemble the unioned types
371
- return `${parameterInfo.name}: ${correctedUnionedTypes.join(" | ")}`;
372
- }
373
-
374
- /**
375
- * Generate the normal import function
376
- */
377
- function generateImportFunction(entry: TypeInfo): string {
378
- const { amdModulePath, esmModulePath, typeName, instanceType = false } = entry;
379
- const functionNameSuffix = convertToPascalCase(amdModulePath);
380
- const promiseType = instanceType ? typeName : `typeof ${typeName}`;
381
-
382
- return `
383
- export async function import${functionNameSuffix}(): Promise<${promiseType}> {
384
- if (isAMD) {
385
- return await window.$arcgis.import("${amdModulePath}");
386
- }
387
- const module = await import("${esmModulePath}");
388
- return isDefaultModule(module) ? module.default : module;
389
- }`;
390
- }
391
-
392
- function upperFirst(s: string): string {
393
- return s[0].toUpperCase() + s.slice(1);
394
- }
395
-
396
- function ignoreModule(s: string): boolean {
397
- return ignoreExports.includes(s);
398
- }
399
-
400
- /**
401
- * Convert a module path to a pascal case name without the `esri/` prefix.
402
- * For example: `esri/identity/IdentityManager` becomes `IdentityIdentityManager`
403
- */
404
- function convertToPascalCase(input: string): string {
405
- // Split the string by slashes and remove any empty strings
406
- const parts = input.replace("esri/", "").split("/").filter(Boolean);
407
-
408
- // Capitalize the first letter of each part
409
- const pascalCaseParts = parts.map(upperFirst);
410
-
411
- // Join the parts together
412
- return pascalCaseParts.join("");
413
- }
414
-
415
- function convertAmdToEsmPath(amdPath: string): string {
416
- return amdPath.replace("esri/", "@arcgis/core/").replace(/(\.js)?$/u, ".js");
417
- }
418
-
419
- generate();
@@ -1,71 +0,0 @@
1
- import fs from "fs";
2
- import https from "https";
3
- import resolvePkg from "resolve-pkg";
4
-
5
- // Get the @arcgis/core installed version
6
- const corePackagePath = resolvePkg("@arcgis/core/package.json");
7
- if (!corePackagePath) {
8
- console.error("Unable to find @arcgis/core package.json");
9
- process.exit(1);
10
- }
11
- const corePackage = JSON.parse(fs.readFileSync(corePackagePath, "utf-8")) as { version: string };
12
- const coreVersion = corePackage.version.split(".").slice(0, 2).join(".");
13
- console.log(`Using ArcGIS Typings version ${coreVersion}`);
14
-
15
- // The typings are hosted on jsapi.esri.com and are versioned based on the system version.
16
- const files = [
17
- {
18
- source: `https://jsapi.esri.com/typings/arcgis-js-api-${coreVersion}.d.ts`,
19
- destination: `${process.cwd()}/support/arcgis.d.ts`,
20
- },
21
- {
22
- source: `https://jsapi.esri.com/typings/api-reference-esm-imports-${coreVersion}.json`,
23
- destination: `${process.cwd()}/support/api-reference-esm-imports.json`,
24
- },
25
- ];
26
-
27
- // Download the typings and support files.
28
- async function downloadSupportFiles(source: string, destination: string): Promise<void> {
29
- try {
30
- fs.unlinkSync(destination);
31
- } catch {
32
- console.log("Error in deleting typings files, continue...");
33
- }
34
-
35
- const file = fs.createWriteStream(destination);
36
-
37
- await new Promise((resolve, reject) => {
38
- https.get(source, (resp) => {
39
- console.log("Downloaded:", source);
40
- console.log(`Response type: ${resp.headers["content-type"]}`);
41
-
42
- resp.pipe(file);
43
-
44
- resp.on("error", (err) => {
45
- console.error(`Request error for ${source}:`, err);
46
- reject(err);
47
- });
48
-
49
- file.on("error", (err) => {
50
- console.error(`Writing error for ${destination}:`, err);
51
- reject(err);
52
- });
53
-
54
- file.on("finish", () => {
55
- file.close();
56
- resolve(undefined);
57
- });
58
- });
59
- });
60
- }
61
-
62
- Promise.allSettled(
63
- files.map(async ({ source, destination }): Promise<void> => await downloadSupportFiles(source, destination)),
64
- )
65
- .then(() => {
66
- console.log(`ArcGIS Typings and support files for ${coreVersion} updated`);
67
- })
68
- .catch((err: Error) => {
69
- console.error(err.message);
70
- process.exit(1);
71
- });