The CodeSearch class provides functionality for searching code across the ServiceNow platform using the Code Search REST API and Table API.
The CodeSearch enables you to:
- Search for code across the entire ServiceNow platform
- Narrow searches to a specific application scope
- Narrow searches to a specific table within a search group
- Retrieve raw hierarchical results or flattened, easy-to-consume results
- List available code search groups
- List tables within a search group
- Add new tables to existing search groups
- Format search results as plain text for CLI output
constructor(instance: ServiceNowInstance)import { ServiceNowInstance, CodeSearch } from '@sonisoft/now-sdk-ext-core';
const codeSearch = new CodeSearch(instance);Search across the ServiceNow platform for code matching a given term. Returns a flattened array of results for easy consumption.
async search(options: CodeSearchOptions): Promise<CodeSearchResult[]>| Parameter | Type | Description |
|---|---|---|
options |
CodeSearchOptions |
Search options including the required search term |
Promise<CodeSearchResult[]> - A flattened array where each entry represents one field match in one record.
Erroriftermis emptyErroriftableis specified withoutsearch_group
const results = await codeSearch.search({ term: 'GlideRecord' });
for (const result of results) {
console.log(`${result.tableLabel} > ${result.name} > ${result.fieldLabel}`);
console.log(` Matches: ${result.matchCount}`);
}Search and return the raw hierarchical response from the API. Results are grouped by record type, then by hit, then by field match.
async searchRaw(options: CodeSearchOptions): Promise<CodeSearchRecordTypeResult[]>| Parameter | Type | Description |
|---|---|---|
options |
CodeSearchOptions |
Search options including the required search term |
Promise<CodeSearchRecordTypeResult[]> - An array of record type groups, each containing hits with field matches.
Erroriftermis emptyErroriftableis specified withoutsearch_group
const rawResults = await codeSearch.searchRaw({ term: 'GlideRecord', limit: 50 });
for (const group of rawResults) {
console.log(`Record Type: ${group.tableLabel} (${group.recordType})`);
console.log(` Hits: ${group.hits.length}`);
}Search for code within a specific application scope. Convenience method that sets current_app and search_all_scopes=false.
async searchInApp(
term: string,
appScope: string,
additionalOptions?: Omit<CodeSearchOptions, 'term' | 'current_app' | 'search_all_scopes'>
): Promise<CodeSearchResult[]>| Parameter | Type | Description |
|---|---|---|
term |
string |
The search term |
appScope |
string |
The application scope to search within (e.g., "x_myapp") |
additionalOptions |
Omit<CodeSearchOptions, ...> |
Optional additional search options |
Promise<CodeSearchResult[]> - Flattened results scoped to the specified application.
const results = await codeSearch.searchInApp('getUserRoles', 'x_myapp');
console.log(`Found ${results.length} matches in x_myapp`);Search for code within a specific table. Convenience method that sets table and search_group.
async searchInTable(
term: string,
tableName: string,
searchGroup: string,
additionalOptions?: Omit<CodeSearchOptions, 'term' | 'table' | 'search_group'>
): Promise<CodeSearchResult[]>| Parameter | Type | Description |
|---|---|---|
term |
string |
The search term |
tableName |
string |
The table to search in |
searchGroup |
string |
The search group name (required when searching by table) |
additionalOptions |
Omit<CodeSearchOptions, ...> |
Optional additional search options |
Promise<CodeSearchResult[]> - Flattened results from the specified table.
const results = await codeSearch.searchInTable(
'GlideRecord',
'sys_script_include',
'sn_global_search'
);
for (const result of results) {
console.log(`${result.name}: ${result.matchCount} matches`);
}List the tables that would be searched for a given search group. Uses the Code Search REST API endpoint.
async getTablesForSearchGroup(searchGroup: string): Promise<CodeSearchTable[]>| Parameter | Type | Description |
|---|---|---|
searchGroup |
string |
The search group NAME |
Promise<CodeSearchTable[]> - Array of table entries with name and optional label.
ErrorifsearchGroupis empty
const tables = await codeSearch.getTablesForSearchGroup('sn_global_search');
for (const table of tables) {
console.log(`${table.label || table.name} (${table.name})`);
}List all available code search groups. Queries the sn_codesearch_search_group table via Table API.
async getSearchGroups(options?: CodeSearchGroupQueryOptions): Promise<CodeSearchGroup[]>| Parameter | Type | Default | Description |
|---|---|---|---|
options |
CodeSearchGroupQueryOptions |
{} |
Optional query and limit options |
Promise<CodeSearchGroup[]> - Array of search group records including sys_id, name, and description.
const groups = await codeSearch.getSearchGroups();
for (const group of groups) {
console.log(`${group.name} (${group.sys_id})`);
if (group.description) {
console.log(` ${group.description}`);
}
}Add a new table to an existing code search group. Inserts a record into the sn_codesearch_table table via Table API POST.
async addTableToSearchGroup(options: AddCodeSearchTableOptions): Promise<CodeSearchTableRecord>| Parameter | Type | Description |
|---|---|---|
options |
AddCodeSearchTableOptions |
The table name, search fields, and search group sys_id |
Promise<CodeSearchTableRecord> - The created record including its sys_id.
Erroriftable,search_fields, orsearch_groupis empty
const record = await codeSearch.addTableToSearchGroup({
table: 'sys_script_include',
search_fields: 'script,name',
search_group: 'abc123def456'
});
console.log(`Added table with sys_id: ${record.sys_id}`);List table records for a search group from the sn_codesearch_table table. Unlike getTablesForSearchGroup() which returns {name, label} from the REST API, this method uses the Table API and returns full records including sys_id.
async getTableRecordsForSearchGroup(
searchGroupSysId: string,
options?: CodeSearchGroupQueryOptions
): Promise<CodeSearchTableRecord[]>| Parameter | Type | Default | Description |
|---|---|---|---|
searchGroupSysId |
string |
- | The sys_id of the search group |
options |
CodeSearchGroupQueryOptions |
{} |
Optional query and limit options |
Promise<CodeSearchTableRecord[]> - Array of full table records including sys_id, table, search_fields, and search_group.
ErrorifsearchGroupSysIdis empty
const tableRecords = await codeSearch.getTableRecordsForSearchGroup('abc123def456');
for (const rec of tableRecords) {
console.log(`${rec.table} - fields: ${rec.search_fields} (${rec.sys_id})`);
}Flatten the hierarchical search API response into a simple array of results. Each entry represents one field match in one record.
static flattenResults(rawResults: CodeSearchRecordTypeResult[]): CodeSearchResult[]| Parameter | Type | Description |
|---|---|---|
rawResults |
CodeSearchRecordTypeResult[] |
The raw record type results from searchRaw() |
CodeSearchResult[] - Flattened array of results.
const rawResults = await codeSearch.searchRaw({ term: 'GlideRecord' });
const flattened = CodeSearch.flattenResults(rawResults);
console.log(`Total field matches: ${flattened.length}`);Format flattened search results as a plain text summary. Useful for CLI output.
static formatResultsAsText(results: CodeSearchResult[]): string| Parameter | Type | Description |
|---|---|---|
results |
CodeSearchResult[] |
Flattened search results from search() |
string - Formatted multi-line text summary.
const results = await codeSearch.search({ term: 'GlideRecord' });
const text = CodeSearch.formatResultsAsText(results);
console.log(text);
// Output:
// Found 5 matches:
//
// Script Includes > MyUtils > Script
// Table: sys_script_include, Field: script, Matches: 3
// L12: var gr = new GlideRecord('incident');
// ...interface CodeSearchOptions {
/** The term to search for (required) */
term: string;
/** The Search Group NAME to search within (not the sys_id) */
search_group?: string;
/** The specific table to search in (requires search_group) */
table?: string;
/** When false, limits results to the scope specified by current_app. Defaults to true */
search_all_scopes?: boolean;
/** Limits results to the specified application scope */
current_app?: string;
/** When true, returns additional fields with match context */
extended_matching?: boolean;
/** Maximum number of results to return */
limit?: number;
}interface CodeSearchGroupQueryOptions {
/** Encoded query string for filtering search groups */
encodedQuery?: string;
/** Maximum number of records to return (default: 100) */
limit?: number;
}interface CodeSearchResult {
/** The table name where the match was found */
table: string;
/** Display label of the table */
tableLabel: string;
/** The name of the record containing the match */
name: string;
/** The field name where the match was found */
field: string;
/** Display label of the field */
fieldLabel: string;
/** Array of line matches within this field */
lineMatches: CodeSearchLineMatch[];
/** Total number of line matches in this field */
matchCount: number;
/** First matching line's context (convenience for display) */
firstMatchContext: string;
/** First matching line number */
firstMatchLine: number;
}interface CodeSearchLineMatch {
/** Line number of the match */
line: number;
/** The matching line content / context snippet */
context: string;
/** HTML-escaped version of the context */
escaped?: string;
}interface CodeSearchFieldMatch {
/** The field name where the match was found (e.g., "script") */
field: string;
/** Display label of the field (e.g., "Script") */
fieldLabel: string;
/** Array of individual line matches within this field */
lineMatches: CodeSearchLineMatch[];
}interface CodeSearchHit {
/** The name/label of the record */
name: string;
/** The table name (className) of the record */
className: string;
/** Display label of the table */
tableLabel: string;
/** Array of field matches within this record */
matches: CodeSearchFieldMatch[];
}interface CodeSearchRecordTypeResult {
/** The table name / record type (e.g., "sys_script_include") */
recordType: string;
/** Display label of the table (e.g., "Script Includes") */
tableLabel: string;
/** Array of record hits within this record type */
hits: CodeSearchHit[];
}interface CodeSearchTable {
/** Table name (e.g., "sys_script_include") */
name: string;
/** Display label of the table */
label?: string;
}interface CodeSearchGroup {
/** System ID */
sys_id: string;
/** Search group name -- used in the search_group parameter */
name: string;
/** Description of the search group */
description?: string;
/** Whether extended matching is enabled */
extended_matching?: string;
/** Sys scope */
sys_scope?: string | { link: string; value: string };
/** Created timestamp */
sys_created_on?: string;
/** Updated timestamp */
sys_updated_on?: string;
}interface AddCodeSearchTableOptions {
/** Table name to add (e.g., "sys_script_include") */
table: string;
/** Comma-separated fields to search (e.g., "script,name") */
search_fields: string;
/** sys_id of the target code search group */
search_group: string;
}interface CodeSearchTableRecord {
/** System ID of this table record */
sys_id: string;
/** The table name (e.g., "sys_script_include") */
table: string;
/** Comma-separated search fields (e.g., "script,name") */
search_fields: string;
/** Reference (sys_id) to the search group */
search_group: string | { link: string; value: string };
/** Created timestamp */
sys_created_on?: string;
/** Updated timestamp */
sys_updated_on?: string;
}async function searchPlatform() {
const codeSearch = new CodeSearch(instance);
const results = await codeSearch.search({ term: 'current.state' });
console.log(CodeSearch.formatResultsAsText(results));
}async function searchAppScope() {
const codeSearch = new CodeSearch(instance);
const results = await codeSearch.searchInApp('getUserRoles', 'x_acme_hr');
console.log(`Found ${results.length} matches in x_acme_hr`);
for (const result of results) {
console.log(` ${result.name} (${result.table}.${result.field}): ${result.matchCount} hits`);
}
}async function discoverSearchGroups() {
const codeSearch = new CodeSearch(instance);
const groups = await codeSearch.getSearchGroups();
for (const group of groups) {
console.log(`\nGroup: ${group.name}`);
if (group.description) {
console.log(` Description: ${group.description}`);
}
const tables = await codeSearch.getTablesForSearchGroup(group.name);
for (const table of tables) {
console.log(` - ${table.label || table.name}`);
}
}
}async function addCustomTable() {
const codeSearch = new CodeSearch(instance);
// Find the target search group
const groups = await codeSearch.getSearchGroups({
encodedQuery: 'name=sn_global_search'
});
if (groups.length === 0) {
console.error('Search group not found');
return;
}
// Add a custom table
const record = await codeSearch.addTableToSearchGroup({
table: 'u_custom_scripts',
search_fields: 'script,name,description',
search_group: groups[0].sys_id
});
console.log(`Added table u_custom_scripts (${record.sys_id})`);
// Verify the table was added
const tableRecords = await codeSearch.getTableRecordsForSearchGroup(groups[0].sys_id);
console.log(`Search group now has ${tableRecords.length} tables`);
}async function deepTableSearch() {
const codeSearch = new CodeSearch(instance);
const rawResults = await codeSearch.searchRaw({
term: 'GlideAggregate',
search_group: 'sn_global_search',
table: 'sys_script_include',
extended_matching: true,
limit: 100
});
for (const group of rawResults) {
console.log(`\n=== ${group.tableLabel} ===`);
for (const hit of group.hits) {
console.log(` Record: ${hit.name}`);
for (const match of hit.matches) {
console.log(` Field: ${match.fieldLabel}`);
for (const lm of match.lineMatches) {
console.log(` Line ${lm.line}: ${lm.context}`);
}
}
}
}
}- Use Flattened Results for Display: Prefer
search()oversearchRaw()for CLI output and simple integrations; usesearchRaw()only when you need the full hierarchical structure - Scope Your Searches: Use
searchInApp()orsearchInTable()to narrow results and improve performance - Provide search_group with table: The API requires
search_groupwhen specifying atable-- omitting it will throw an error - Set Reasonable Limits: Use the
limitoption to cap result counts, especially on large instances - Use formatResultsAsText for CLI: The static
formatResultsAsText()method provides well-structured output suitable for terminal display - Distinguish Table Listing Methods: Use
getTablesForSearchGroup()(by name) for quick lookups andgetTableRecordsForSearchGroup()(by sys_id) when you need full records with sys_id