
Company News
/Security News
Socket Selected for OpenAI's Cybersecurity Grant Program
Socket is an initial recipient of OpenAI's Cybersecurity Grant Program, which commits $10M in API credits to defenders securing open source software.
esm-analyzer
Advanced tools
The scanner and analyzer of ESM.
pnpm i esm-analyzer
The scanner uses @babel/parser to parse the source code and find the import and export statements.
import { scan } from 'esm-analyzer'
const { imports, exports } = scan(sourceCode, lang)
langThe lang parameter is used to specify the language of the source code.
It can be one of the following values:
jsjsxtstsximports scannerimport foo from 'bar'import * as foo from 'bar'import { foo } from 'bar'import { foo as bar } from 'bar'import type { foo } from 'bar' or import { type foo } from 'bar'The imports type is defined as follows:
interface ScanResultBase {
source: string
loc: ASTNodeLocation
}
// import a from 'a'
interface ScanImportResultDefault extends ScanResultBase {
type: 'default'
local: string // a
}
// import * as a from 'a'
interface ScanImportResultNamespace extends ScanResultBase {
type: 'namespace'
local: string // a
}
// import { a as b } from 'a'
interface ScanImportResultImport extends ScanResultBase {
type: 'import'
subType: 'id' | 'string' // id: `import { a } from 'a'`; string: `import { 'a' } from 'a'`
isType: boolean // `import type { a } from 'a'` or `import { type a } from 'a'`
local: string // b
imported: string // a
}
type ScanImportResultItem = ScanImportResultDefault | ScanImportResultNamespace | ScanImportResultImport
The imports is an array of ScanImportResultItem.
The basic example:
const code = 'import foo from "bar"'
scan(code, 'js').imports
will be:
[
{
loc: {
end: {
column: 10,
index: 10,
line: 1,
},
start: {
column: 7,
index: 7,
line: 1,
},
},
local: 'foo',
source: 'bar',
type: 'default',
},
]
Also, you can use the standalone import scanner API(with loadScanner helper):
import { loadScanner } from 'esm-analyzer'
const importResults = loadScanner(sourceCode, lang, node => scanImport(node))
The scanImport function accepts a config object as the second parameter:
interface ScanImportConfig {
includeSource?: string[] // the source list to be included
excludeSource?: string[] // the source list to be excluded
skipType?: boolean // whether to skip the type import
}
const defaultConfig: Required<ScanImportConfig> = {
includeSource: [],
excludeSource: [],
skipType: false,
}
variable declarations scannerThe variable declarations is an array of ScanVariableDeclarationResult.
StringLiteralNumericLiteralBooleanLiteralNullLiteralObjectExpressionArrayExpressionCallExpressionThe ScanVariableDeclarationResult is defined as follows:
export interface ScanVariableDeclarationResult {
loc: ASTNodeLocation
kind: t.VariableDeclaration['kind']
name: string
init: ResolveVariableDeclaration
}
The basic example:
const code = 'const foo = "bar"'
scan(code, 'js').variables
The output will be:
[
{
init: {
type: 'StringLiteral',
value: 'bar',
},
kind: 'const',
loc: {
end: {
column: 17,
index: 17,
line: 1,
},
start: {
column: 6,
index: 6,
line: 1,
},
},
name: 'foo',
},
]
Also, you can use the standalone variable scanner API(with loadScanner helper):
import { loadScanner } from 'esm-analyzer'
const importResults = loadScanner(sourceCode, lang, node => scanVariableDeclaration(node))
The scanVariableDeclaration function accepts a config object as the second parameter:
export type VariableType =
| 'StringLiteral'
| 'NumericLiteral'
| 'BooleanLiteral'
| 'NullLiteral'
| 'ObjectExpression'
| 'ArrayExpression'
| 'CallExpression'
interface ScanVariableDeclarationConfig {
includeType?: VariableType[]
excludeType?: VariableType[]
}
export scannerexport default fooexport { foo }
Identifier and primitiveexport { foo as bar }export * from 'foo'export type { foo } from 'bar'export { type foo } from 'bar'The exports type is defined as follows, will return ScanExportResult[]
export interface ScanExportNamedDeclarationResult {
type: 'ExportNamedDeclaration'
subType: 'VariableDeclaration'
kind: t.VariableDeclaration['kind']
declarations: {
name: string
init: ResolveVariableDeclaration
}[]
}
export interface ScanExportNamedSpecifiersResult {
type: 'ExportNamedDeclaration'
subType: 'Specifiers'
specifiers: {
local: string
exported: string
}[]
source: string | null
}
export interface ScanExportAllResult {
type: 'ExportAllDeclaration'
source: string
}
export interface ScanExportDefaultIdentifierResult {
type: 'ExportDefaultDeclaration'
subType: 'Identifier'
id: string
}
export interface ScanExportDefaultObjectResult {
type: 'ExportDefaultDeclaration'
subType: 'ObjectExpression'
properties: {
key: string
value: ResolveVariableDeclaration
}[]
}
export type ScanExportResult = (
| ScanExportNamedDeclarationResult
| ScanExportNamedSpecifiersResult
| ScanExportAllResult
| ScanExportDefaultIdentifierResult
| ScanExportDefaultObjectResult
) & {
loc: ASTNodeLocation
}
The basic example:
const code = 'export default { a: 1, b: 2 }'
scan(code, 'js').exports
The result will be:
[
{
loc: {
end: {
column: 7,
index: 58,
line: 5,
},
start: {
column: 6,
index: 7,
line: 2,
},
},
properties: [
{
key: 'a',
value: {
type: 'NumericLiteral',
value: 1,
},
},
{
key: 'b',
value: {
type: 'NumericLiteral',
value: 2,
},
},
],
subType: 'ObjectExpression',
type: 'ExportDefaultDeclaration',
},
]
Also, you can use the standalone export scanner API(with loadScanner helper):
import { loadScanner } from 'esm-analyzer'
const importResults = loadScanner(sourceCode, lang, node => scanExport(node))
The scanExport function accepts a config object as the second parameter:
export type ScanExportType =
| 'ExportNamedDeclaration'
| 'ExportAllDeclaration'
| 'ExportDefaultDeclaration'
interface ScanExportConfig {
includeType?: ScanExportType[]
excludeType?: ScanExportType[]
}
use analyze you can find all the variable declarations and their import statement and export statement
const code1 = {
filename: '/src/bar.js',
code: `
export const bar = 'bar'
`,
}
const code2 = {
filename: '/src/foo.js',
code: `
import { bar, ref } from './bar'
export const foo = bar
const foo2 = ref(1)
`,
}
const p = new Project('test')
p.addFile(code1.filename, code1.code)
p.addFile(code2.filename, code2.code)
await p.prepare()
const c = p.findAnalyzeResults(code2.filename)
expect(c).toMatchSnapshot()
The result is map, and it's entries is:
[
[
{
init: {
id: 'bar',
type: 'Identifier',
},
kind: 'const',
loc: {
end: {
column: 28,
index: 68,
line: 3,
},
start: {
column: 19,
index: 59,
line: 3,
},
},
name: 'foo',
},
{
fromExport: {
declarations: [
{
init: {
type: 'StringLiteral',
value: 'bar',
},
name: 'bar',
},
],
kind: 'const',
loc: {
end: {
column: 30,
index: 31,
line: 2,
},
start: {
column: 6,
index: 7,
line: 2,
},
},
subType: 'VariableDeclaration',
type: 'ExportNamedDeclaration',
},
fromImport: {
imported: 'bar',
isType: false,
loc: {
end: {
column: 18,
index: 19,
line: 2,
},
start: {
column: 15,
index: 16,
line: 2,
},
},
local: 'bar',
source: './bar',
subType: 'id',
type: 'import',
},
id: 'bar',
importFile: '/src/bar.js',
type: 'Identifier',
},
],
[
{
init: {
arguments: [
{
type: 'NumericLiteral',
value: 1,
},
],
callee: 'ref',
type: 'CallExpression',
},
kind: 'const',
loc: {
end: {
column: 25,
index: 94,
line: 4,
},
start: {
column: 12,
index: 81,
line: 4,
},
},
name: 'foo2',
},
{
arguments: [
{
type: 'NumericLiteral',
value: 1,
},
],
callee: 'ref',
calleeFrom: {
imported: 'ref',
isType: false,
loc: {
end: {
column: 23,
index: 24,
line: 2,
},
start: {
column: 20,
index: 21,
line: 2,
},
},
local: 'ref',
source: './bar',
subType: 'id',
type: 'import',
},
type: 'CallExpression',
},
],
]
MIT
FAQs
The scanner and analyzer of ESM.
The npm package esm-analyzer receives a total of 13 weekly downloads. As such, esm-analyzer popularity was classified as not popular.
We found that esm-analyzer demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Company News
/Security News
Socket is an initial recipient of OpenAI's Cybersecurity Grant Program, which commits $10M in API credits to defenders securing open source software.

Security News
Socket CEO Feross Aboukhadijeh joins 10 Minutes or Less, a podcast by Ali Rohde, to discuss the recent surge in open source supply chain attacks.

Research
/Security News
Campaign of 108 extensions harvests identities, steals sessions, and adds backdoors to browsers, all tied to the same C2 infrastructure.